diff --git a/config/services.yaml b/config/services.yaml index dbe9698e..34fd7498 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -201,6 +201,18 @@ services: # rider assignment interface #App\Service\RiderAssignmentHandlerInterface: "@App\\Service\\RiderAssignmentHandler\\CMBRiderAssignmentHandler" + # rider API service + App\Service\RiderAPIHandler\CMBRiderAPIHandler: + arguments: + $country_code: "%env(COUNTRY_CODE)%" + + #App\Service\RiderAPIHandler\ResqRiderAPIHandler: + # arguments: + # $country_code: "%env(COUNTRY_CODE)%" + + # rider API interface + App\Service\RiderAPIHandlerInterface: "@App\\Service\\RiderAPIHandler\\CMBRiderAPIHandler" + # map manager #App\Service\GISManager\Bing: ~ App\Service\GISManager\OpenStreet: ~ diff --git a/src/Controller/RAPIController.php b/src/Controller/RAPIController.php index e583de75..3b8bdab1 100644 --- a/src/Controller/RAPIController.php +++ b/src/Controller/RAPIController.php @@ -2,994 +2,302 @@ namespace App\Controller; -use Doctrine\ORM\Query; -use Doctrine\ORM\QueryBuilder; -use Doctrine\DBAL\DBALException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; - -use CrEOF\Spatial\PHP\Types\Geometry\Point; use App\Ramcar\APIResult; -use App\Ramcar\JOStatus; -use App\Ramcar\InvoiceCriteria; -use App\Ramcar\CMBServiceType; -use App\Ramcar\ServiceType; -use App\Ramcar\WarrantyClass; -use App\Ramcar\APIRiderStatus; -use App\Ramcar\TransactionOrigin; -use App\Ramcar\CMBTradeInType; -use App\Ramcar\TradeInType; -use App\Ramcar\InvoiceStatus; -use App\Ramcar\ModeOfPayment; -use App\Ramcar\JOEventType; -use App\Service\InvoiceGeneratorInterface; -use App\Service\MQTTClient; -use App\Service\WarrantyHandler; -use App\Service\RedisClientProvider; -use App\Service\RiderCache; - -use App\Entity\RiderSession; -use App\Entity\Customer; -use App\Entity\VehicleManufacturer; -use App\Entity\Vehicle; -use App\Entity\CustomerVehicle; -use App\Entity\JobOrder; -use App\Entity\Promo; -use App\Entity\Battery; -use App\Entity\BatteryModel; -use App\Entity\BatterySize; -use App\Entity\RiderRating; -use App\Entity\Rider; -use App\Entity\User; -use App\Entity\JOEvent; -use App\Entity\Warranty; - -use DateTime; -use DateInterval; +use App\Service\RiderAPIHandlerInterface; // Rider API controller -// TODO: Need to refactor this into a service class RAPIController extends Controller { - protected $session; - - public function __construct() - { - // 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 - // when a rider logs out, we remove the rider assigned to the device - $this->session = null; - } - - protected function checkMissingParameters(Request $req, $params = []) - { - $missing = []; - - // check if parameters are there - foreach ($params as $param) - { - if ($req->getMethod() == 'GET') - { - $check = $req->query->get($param); - if ($check == null) - $missing[] = $param; - } - else if ($req->getMethod() == 'POST') - { - $check = $req->request->get($param); - if ($check == null) - $missing[] = $param; - } - else - return $params; - } - - return $missing; - } - - // TODO: type hint entity manager - protected function checkAPIKey($em, $api_key) - { - // find the api key (session id) - $session = $em->getRepository(RiderSession::class)->find($api_key); - if ($session == null) - return null; - - return $session; - } - - protected function checkParamsAndKey(Request $req, $em, $params) - { - // returns APIResult object - $res = new APIResult(); - - // check for api_key in query string - $api_key = $req->query->get('api_key'); - if (empty($api_key)) - { - $res->setError(true) - ->setErrorMessage('Missing API key'); - return $res; - } - - // check missing parameters - $missing = $this->checkMissingParameters($req, $params); - if (count($missing) > 0) - { - $miss_string = implode(', ', $missing); - $res->setError(true) - ->setErrorMessage('Missing parameter(s): ' . $miss_string); - return $res; - } - - // check api key - $sess = $this->checkAPIKey($em, $req->query->get('api_key')); - if ($sess == null) - { - $res->setError(true) - ->setErrorMessage('Invalid API Key'); - return $res; - } - - // store session - $this->session = $sess; - - return $res; - } - - public function register(Request $req, RedisClientProvider $redis) + public function register(Request $req, RiderAPIHandlerInterface $rapi_handler) { $res = new APIResult(); - // confirm parameters - $required_params = [ - 'phone_number', - 'device_push_id' - ]; + $data = $rapi_handler->register($req); - $missing = $this->checkMissingParameters($req, $required_params); - if (count($missing) > 0) + if (isset($data['error'])) { - $params = implode(', ', $missing); + $message = $data['error']; + $res->setError(true) - ->setErrorMessage('Missing parameter(s): ' . $params); - return $res->getReturnResponse(); + ->setErrorMessage($message); } - - $em = $this->getDoctrine()->getManager(); - - // retry until we get a unique id - while (true) + else { - try - { - // instantiate session - $sess = new RiderSession(); - $sess->setPhoneNumber($req->request->get('phone_number')) - ->setDevicePushID($req->request->get('device_push_id')); - - // reopen in case we get an exception - if (!$em->isOpen()) - { - $em = $em->create( - $em->getConnection(), - $em->getConfiguration() - ); - } - - // save - $em->persist($sess); - $em->flush(); - - // create redis entry for the session - $redis_client = $redis->getRedisClient(); - $redis_key = 'rider.id.' . $sess->getID(); - error_log('redis_key: ' . $redis_key); - $redis_client->set($redis_key, ''); - } - catch (DBALException $e) - { - error_log($e->getMessage()); - // delay one second and try again - sleep(1); - continue; - } - - break; + $res->setData($data); } - // return data - $data = [ - 'session_id' => $sess->getID() - ]; - $res->setData($data); - - // response return $res->getReturnResponse(); } - public function login(Request $req, EncoderFactoryInterface $ef, RedisClientProvider $redis, RiderCache $rcache) + public function login(Request $req, RiderAPIHandlerInterface $rapi_handler) { - $required_params = [ - 'user', - 'pass', - ]; - $em = $this->getDoctrine()->getManager(); - $res = $this->checkParamsAndKey($req, $em, $required_params); - if ($res->isError()) - return $res->getReturnResponse(); + $res = new APIResult(); - // check if session has a rider already - if ($this->session->hasRider()) + $data = $rapi_handler->login($req); + + if (isset($data['error'])) { + $message = $data['error']; + $res->setError(true) - ->setErrorMessage('Another rider is already logged in. Please logout first.'); - return $res->getReturnResponse(); - } - - // look for rider with username - $rider = $em->getRepository(Rider::class)->findOneBy(['username' => $req->request->get('user')]); - if ($rider == null) - { - $res->setError(true) - ->setErrorMessage('Invalid username or password.'); - return $res->getReturnResponse(); - } - - // check if rider password is correct - $encoder = $ef->getEncoder(new User()); - if (!$encoder->isPasswordValid($rider->getPassword(), $req->request->get('pass'), '')) - { - $res->setError(true) - ->setErrorMessage('Invalid username or password.'); - return $res->getReturnResponse(); - } - - // assign rider to session - $this->session->setRider($rider); - - $rider->setAvailable(true); - - $rider_id = $rider->getID(); - // cache rider location (default to hub) - // TODO: figure out longitude / latitude default - $rcache->addActiveRider($rider_id, 0, 0); - - // TODO: log rider logging in - - $em->flush(); - - // update redis rider.id. with the rider id - $redis_client = $redis->getRedisClient(); - $redis_key = 'rider.id.' . $this->session->getID(); - $rider_id = $rider->getID(); - - $redis_client->set($redis_key, $rider_id); - - $hub = $rider->getHub(); - if ($hub == null) - $hub_data = null; - else - { - $coord = $hub->getCoordinates(); - $hub_data = [ - 'id' => $hub->getID(), - 'name' => $hub->getName(), - 'branch' => $hub->getBranch(), - 'longitude' => $coord->getLongitude(), - 'latitude' => $coord->getLatitude(), - 'contact_nums' => $hub->getContactNumbers(), - ]; - } - - // data - $data = [ - 'hub' => $hub_data, - 'rider_id' => $rider_id, - ]; - - $res->setData($data); - - return $res->getReturnResponse(); - } - - public function logout(Request $req, RiderCache $rcache) - { - $required_params = []; - $em = $this->getDoctrine()->getManager(); - $res = $this->checkParamsAndKey($req, $em, $required_params); - if ($res->isError()) - return $res->getReturnResponse(); - - // make rider unavailable - $rider = $this->session->getRider(); - $rider->setAvailable(false); - - // remove from cache - $rcache->removeActiveRider($rider->getID()); - - // remove rider from session - $this->session->setRider(null); - - // TODO: log rider logging out - - $em->flush(); - - return $res->getReturnResponse(); - } - - public function getJobOrder(Request $req) - { - // get the job order of the rider assigned to this session - $required_params = []; - $em = $this->getDoctrine()->getManager(); - $res = $this->checkParamsAndKey($req, $em, $required_params); - if ($res->isError()) - return $res->getReturnResponse(); - - // are we logged in? - if (!$this->session->hasRider()) - { - $res->setError(true) - ->setErrorMessage('No logged in rider.'); - return $res->getReturnResponse(); - } - - $rider = $this->session->getRider(); - - // do we have a job order? - $jo = $rider->getActiveJobOrder(); - if ($jo == null) - { - $data = [ - 'job_order' => null - ]; + ->setErrorMessage($message); } else { - $coord = $jo->getCoordinates(); - $cust = $jo->getCustomer(); - $cv = $jo->getCustomerVehicle(); - $v = $cv->getVehicle(); - $inv = $jo->getInvoice(); - $promo = $inv->getPromo(); - - // invoice items - $inv_items = []; - foreach ($inv->getItems() as $item) - { - $item_batt = $item->getBattery(); - if ($item_batt == null) - $batt_id = null; - else - $batt_id = $item_batt->getID(); - - $inv_items[] = [ - 'id' => $item->getID(), - 'title' => $item->getTitle(), - 'qty' => $item->getQuantity(), - 'price' => $item->getPrice(), - 'batt_id' => $batt_id, - ]; - } - - // promo - if ($promo != null) - { - $promo_data = [ - 'id' => $promo->getID(), - 'name' => $promo->getName(), - 'code' => $promo->getCode(), - 'discount_rate' => $promo->getDiscountRate(), - 'discount_apply' => $promo->getDiscountApply(), - ]; - } - else - { - $promo_data = null; - } - - $trade_in_type = $jo->getTradeInType(); - if (empty($trade_in_type)) - $trade_in_type = 'none'; - - - $data = [ - 'job_order' => [ - 'id' => $jo->getID(), - 'service_type' => $jo->getServiceType(), - 'date_schedule' => $jo->getDateSchedule()->format('Ymd H:i:s'), - 'longitude' => $coord->getLongitude(), - 'latitude' => $coord->getLatitude(), - 'status' => $jo->getStatus(), - 'customer' => [ - 'title' => $cust->getTitle(), - 'first_name' => $cust->getFirstName(), - 'last_name' => $cust->getLastName(), - 'phone_mobile' => '63' . $cust->getPhoneMobile(), - ], - 'vehicle' => [ - 'manufacturer' => $v->getManufacturer()->getName(), - 'make' => $v->getMake(), - 'model' => $cv->getModelYear(), - 'plate_number' => $cv->getPlateNumber(), - 'color' => $cv->getColor(), - ], - 'or_num' => $jo->getORNum(), - 'or_name' => $jo->getORName(), - 'delivery_instructions' => $jo->getDeliveryInstructions(), - 'delivery_address' => $jo->getDeliveryAddress(), - 'landmark' => $jo->getLandmark(), - 'invoice' => [ - 'discount' => $inv->getDiscount(), - 'trade_in' => $inv->getTradeIn(), - 'total_price' => $inv->getTotalPrice(), - 'vat' => $inv->getVat(), - 'items' => $inv_items, - ], - 'mode_of_payment' => $jo->getModeOfPayment(), - 'trade_in_type' => $trade_in_type, - 'promo' => $promo_data, - // TODO: load the actual - 'has_warranty_doc' => false, - 'flag_coolant' => $jo->hasCoolant(), - 'has_motolite' => $cv->hasMotoliteBattery(), - ] - ]; + $res->setData($data); } - $res->setData($data); - + // response return $res->getReturnResponse(); } - protected function checkJO(Request $req, $required_params, &$jo = null) + public function logout(Request $req, RiderAPIHandlerInterface $rapi_handler) { - // set jo status to in transit - $em = $this->getDoctrine()->getManager(); - $res = $this->checkParamsAndKey($req, $em, $required_params); - if ($res->isError()) - return $res; + $res = new APIResult(); - // are we logged in? - if (!$this->session->hasRider()) + $data = $rapi_handler->logout($req); + + if (isset($data['error'])) { + $message = $data['error']; + $res->setError(true) - ->setErrorMessage('No logged in rider.'); - return $res; + ->setErrorMessage($message); + } + else + { + $res->setData($data); } - $rider = $this->session->getRider(); + // response + return $res->getReturnResponse(); + } - // check if we have an active JO - $jo = $rider->getActiveJobOrder(); - if ($jo == null) + public function getJobOrder(Request $req, RiderAPIHandlerInterface $rapi_handler) + { + $res = new APIResult(); + + $data = $rapi_handler->getJobOrder($req); + + if (isset($data['error'])) { + $message = $data['error']; + $res->setError(true) - ->setErrorMessage('No active job order.'); - return $res; + ->setErrorMessage($message); + } + else + { + $res->setData($data); } - // check if the jo_id sent is the same as our active jo - if ($req->request->get('jo_id') != $jo->getID()) + // response + return $res->getReturnResponse(); + } + + public function acceptJobOrder(Request $req, RiderAPIHandlerInterface $rapi_handler) + { + $res = new APIResult(); + + $data = $rapi_handler->acceptJobOrder($req); + + if (isset($data['error'])) { + $message = $data['error']; + $res->setError(true) - ->setErrorMessage('Job order selected is not active job order.'); - return $res; + ->setErrorMessage($message); + } + else + { + $res->setData($data); } - return $res; - } - - public function acceptJobOrder(Request $req) - { - $em = $this->getDoctrine()->getManager(); - $required_params = ['jo_id']; - $res = $this->checkJO($req, $required_params, $jo); - if ($res->isError()) - return $res->getReturnResponse(); - - // TODO: refactor this into a jo handler class, so we don't have to repeat for control center - - // set jo status to in transit - $jo->setStatus(JOStatus::IN_TRANSIT); - - // TODO: send mqtt event (?) - - // add event log - $rider = $this->session->getRider(); - $event = new JOEvent(); - $event->setDateHappen(new DateTime()) - ->setTypeID(JOEventType::RIDER_ACCEPT) - ->setJobOrder($jo) - ->setRider($rider); - $em->persist($event); - - $em->flush(); - + // response return $res->getReturnResponse(); } - public function cancelJobOrder(Request $req, MQTTClient $mclient) + public function cancelJobOrder(Request $req, RiderAPIHandlerInterface $rapi_handler) { - $em = $this->getDoctrine()->getManager(); - $required_params = ['jo_id']; - $res = $this->checkJO($req, $required_params, $jo); - if ($res->isError()) - return $res->getReturnResponse(); + $res = new APIResult(); - // $jo->cancel("rider cancelled"); - // requeue it, instead of cancelling it - $jo->requeue(); + $data = $rapi_handler->cancelJobOrder($req); - // add event log - $rider = $this->session->getRider(); - $event = new JOEvent(); - $event->setDateHappen(new DateTime()) - ->setTypeID(JOEventType::REQUEUE) - ->setJobOrder($jo) - ->setRider($rider); - $em->persist($event); - - $em->flush(); - - // send mqtt event - // send outlet assign since order should go back to hub and await reassignment to another rider - $payload = [ - 'event' => 'outlet_assign', - 'jo_id' => $jo->getID(), - ]; - $mclient->sendEvent($jo, $payload); - - - - return $res->getReturnResponse(); - } - - public function arrive(Request $req, MQTTClient $mclient) - { - $em = $this->getDoctrine()->getManager(); - $required_params = ['jo_id']; - $res = $this->checkJO($req, $required_params, $jo); - if ($res->isError()) - return $res->getReturnResponse(); - - // TODO: refactor this into a jo handler class, so we don't have to repeat for control center - - // set jo status to in progress - $jo->setStatus(JOStatus::IN_PROGRESS); - - // add event log - $rider = $this->session->getRider(); - $event = new JOEvent(); - $event->setDateHappen(new DateTime()) - ->setTypeID(JOEventType::RIDER_ARRIVE) - ->setJobOrder($jo) - ->setRider($rider); - $em->persist($event); - - $em->flush(); - - // send mqtt event - $rider = $this->session->getRider(); - $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/assets/images/user.gif'; - if ($rider->getImageFile() != null) - $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/uploads/' . $rider->getImageFile(); - - $payload = [ - 'event' => 'driver_arrived', - 'jo_id' => $jo->getID(), - 'driver_image' => $image_url, - 'driver_name' => $rider->getFullName(), - 'driver_id' => $rider->getID(), - ]; - $mclient->sendEvent($jo, $payload); - - - return $res->getReturnResponse(); - } - - public function hubArrive(Request $req) - { - $required_params = []; - $em = $this->getDoctrine()->getManager(); - $res = $this->checkParamsAndKey($req, $em, $required_params); - if ($res->isError()) - return $res->getReturnResponse(); - - // are we logged in? - if (!$this->session->hasRider()) + if (isset($data['error'])) { + $message = $data['error']; + $res->setError(true) - ->setErrorMessage('No logged in rider.'); - return $res->getReturnResponse(); + ->setErrorMessage($message); + } + else + { + $res->setData($data); } - // TODO: tag rider as available + // response + return $res->getReturnResponse(); - $em->flush(); + } + public function arrive(Request $req, RiderAPIHandlerInterface $rapi_handler) + { + $res = new APIResult(); + $data = $rapi_handler->arrive($req); + + if (isset($data['error'])) + { + $message = $data['error']; + + $res->setError(true) + ->setErrorMessage($message); + } + else + { + $res->setData($data); + } + + // response return $res->getReturnResponse(); } - public function payment(Request $req, MQTTClient $mclient, WarrantyHandler $wh) + public function hubArrive(Request $req, RiderAPIHandlerInterface $rapi_handler) { - $em = $this->getDoctrine()->getManager(); - $required_params = ['jo_id']; - $res = $this->checkJO($req, $required_params, $jo); - if ($res->isError()) - return $res->getReturnResponse(); + $res = new APIResult(); - // set invoice to paid - $jo->getInvoice()->setStatus(InvoiceStatus::PAID); + $data = $rapi_handler->hubArrive($req); - /* - // set jo status to fulfilled - $jo->setStatus(JOStatus::FULFILLED); - */ - $jo->fulfill(); - - // add event log - $rider = $this->session->getRider(); - $event = new JOEvent(); - $event->setDateHappen(new DateTime()) - ->setTypeID(JOEventType::FULFILL) - ->setJobOrder($jo) - ->setRider($rider); - $em->persist($event); - - // TODO: tag rider as unavailable - - // save to customer vehicle battery record - // TODO: this has to move to JOHandler - $this->updateVehicleBattery($jo); - - // create warranty - if (($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) || - ($jo->getServiceType() == CMBServiceType::BATTERY_REPLACEMENT_NEW)) + if (isset($data['error'])) { - $serial = null; - $warranty_class = $jo->getWarrantyClass(); - $first_name = $jo->getCustomer()->getFirstName(); - $last_name = $jo->getCustomer()->getLastName(); - $mobile_number = $jo->getCustomer()->getPhoneMobile(); + $message = $data['error']; - // check if date fulfilled is null - if ($jo->getDateFulfill() == null) - $date_purchase = $jo->getDateCreate(); - else - $date_purchase = $jo->getDateFulfill(); - - $plate_number = $wh->cleanPlateNumber($jo->getCustomerVehicle()->getPlateNumber()); - - $batt_list = array(); - $invoice = $jo->getInvoice(); - if (!empty($invoice)) - { - // get battery - $invoice_items = $invoice->getItems(); - foreach ($invoice_items as $item) - { - $battery = $item->getBattery(); - if ($battery != null) - { - $batt_list[] = $item->getBattery(); - } - } - } - - $wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class); + $res->setError(true) + ->setErrorMessage($message); + } + else + { + $res->setData($data); } - // send mqtt event (fulfilled) - $rider = $this->session->getRider(); - $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/assets/images/user.gif'; - if ($rider->getImageFile() != null) - $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/uploads/' . $rider->getImageFile(); - $payload = [ - 'event' => 'fulfilled', - 'jo_id' => $jo->getID(), - 'driver_image' => $image_url, - 'driver_name' => $rider->getFullName(), - 'driver_id' => $rider->getID(), - ]; - $mclient->sendEvent($jo, $payload); + // response + return $res->getReturnResponse(); + } + public function payment(Request $req, RiderAPIHandlerInterface $rapi_handler) + { + $res = new APIResult(); + + $data = $rapi_handler->payment($req); + + if (isset($data['error'])) + { + $message = $data['error']; + + $res->setError(true) + ->setErrorMessage($message); + } + else + { + $res->setData($data); + } + + // response return $res->getReturnResponse(); } - public function available(Request $req) + public function available(Request $req, RiderAPIHandlerInterface $rapi_handler) { - $em = $this->getDoctrine()->getManager(); - $required_params = []; - $res = $this->checkParamsAndKey($req, $em, $required_params); - if ($res->isError()) - return $res->getReturnResponse(); + $res = new APIResult(); - // make rider available - $this->session->getRider()->setAvailable(true); + $data = $rapi_handler->available($req); - // TODO: log rider available - $em->flush(); - - return $res->getReturnResponse(); - } - - public function getPromos(Request $req) - { - $em = $this->getDoctrine()->getManager(); - $required_params = []; - $res = $this->checkParamsAndKey($req, $em, $required_params); - if ($res->isError()) - return $res->getReturnResponse(); - - $promos = $em->getRepository(Promo::class)->findAll(); - - $promo_data = []; - foreach ($promos as $promo) + if (isset($data['error'])) { - $promo_data[] = [ - 'id' => $promo->getID(), - 'name' => $promo->getName(), - 'code' => $promo->getCode(), - ]; - } + $message = $data['error']; - $data = [ - 'promos' => $promo_data, - ]; - $res->setData($data); - return $res->getReturnResponse(); - } - - public function getBatteries(Request $req) - { - // get batteries, models, and sizes - $em = $this->getDoctrine()->getManager(); - $required_params = []; - $res = $this->checkParamsAndKey($req, $em, $required_params); - if ($res->isError()) - return $res->getReturnResponse(); - - $batts = $em->getRepository(Battery::class)->findAll(); - $models = $em->getRepository(BatteryModel::class)->findAll(); - $sizes = $em->getRepository(BatterySize::class)->findAll(); - - $batt_data = []; - foreach ($batts as $batt) - { - $batt_data[] = [ - 'id' => $batt->getID(), - 'model_id' => $batt->getModel()->getID(), - 'size_id' => $batt->getSize()->getID(), - 'sell_price' => $batt->getSellingPrice(), - ]; - } - - $model_data = []; - foreach ($models as $model) - { - $model_data[] = [ - 'id' => $model->getID(), - 'name' => $model->getName(), - ]; - } - - $size_data = []; - foreach ($sizes as $size) - { - $size_data[] = [ - 'id' => $size->getID(), - 'name' => $size->getName(), - ]; - } - - $data = [ - 'batteries' => $batt_data, - 'models' => $model_data, - 'sizes' => $size_data, - ]; - - $res->setData($data); - return $res->getReturnResponse(); - } - - protected function debugRequest(Request $req) - { - $all = $req->request->all(); - error_log(print_r($all, true)); - } - - public function changeService(Request $req, InvoiceGeneratorInterface $ic) - { - $this->debugRequest($req); - - // allow rider to change service, promo, battery and trade-in options - $em = $this->getDoctrine()->getManager(); - $required_params = ['jo_id', 'stype_id', 'promo_id']; - $res = $this->checkJO($req, $required_params, $jo); - if ($res->isError()) - return $res->getReturnResponse(); - - // check service type - $stype_id = $req->request->get('stype_id'); - if ((!CMBServiceType::validate($stype_id)) || - (!ServiceType::validate($stype_id))) - { $res->setError(true) - ->setErrorMessage('Invalid service type - ' . $stype_id); - return $res->getReturnResponse(); + ->setErrorMessage($message); } - - // check promo id - $promo_id = $req->request->get('promo_id'); - // no promo - if ($promo_id == 0) - $promo = null; else { - $promo = $em->getRepository(Promo::class)->find($promo_id); - if ($promo == null) - { - $res->setError(true) - ->setErrorMessage('Invalid promo id - ' . $promo_id); - return $res->getReturnResponse(); - } + $res->setData($data); } - // check or number - $or_num = $req->request->get('or_num'); - if ($or_num != null) - $jo->setORNum($or_num); - - // coolant - $flag_coolant = $req->request->get('flag_coolant', 'false'); - if ($flag_coolant == 'true') - $jo->setHasCoolant(true); - else - $jo->setHasCoolant(false); - - // has motolite battery - $cv = $jo->getCustomerVehicle(); - $has_motolite = $req->request->get('has_motolite', 'false'); - if ($has_motolite == 'true') - $cv->setHasMotoliteBattery(true); - else - $cv->setHasMotoliteBattery(false); - $em->persist($cv); - - // check battery id - $batt_id = $req->request->get('batt_id', null); - // no battery - if ($batt_id == 0 || $batt_id == null) - $battery = null; - else - { - $battery = $em->getRepository(Battery::class)->find($batt_id); - if ($battery == null) - { - $res->setError(true) - ->setErrorMessage('Invalid battery id - ' . $batt_id); - return $res->getReturnResponse(); - } - } - - // check trade in - $trade_in = $req->request->get('trade_in'); - if ((!CMBTradeInType::validate($trade_in)) || - (!TradeInType::validate($trade_in))) - $trade_in = null; - - // check mode of payment - $mode = $req->request->get('mode_of_payment'); - if (!ModeOfPayment::validate($mode)) - $mode = ModeOfPayment::CASH; - $jo->setModeOfPayment($mode); - - - // generate new invoice - $crit = new InvoiceCriteria(); - $crit->setServiceType($stype_id); - $crit->setCustomerVehicle($cv); - $crit->setHasCoolant($jo->hasCoolant()); - - if ($promo != null) - $crit->addPromo($promo); - - if ($battery != null) - { - $crit->addEntry($battery, $trade_in, 1); - error_log('adding entry for battery - ' . $battery->getID()); - } - - $invoice = $ic->generateInvoice($crit); - - // remove previous invoice - $old_invoice = $jo->getInvoice(); - $em->remove($old_invoice); - $em->flush(); - - // save job order - $jo->setServiceType($stype_id); - - // save invoice - $jo->setInvoice($invoice); - $em->persist($invoice); - - // add event log - $rider = $this->session->getRider(); - $event = new JOEvent(); - $event->setDateHappen(new DateTime()) - ->setTypeID(JOEventType::RIDER_EDIT) - ->setJobOrder($jo) - ->setRider($rider); - $em->persist($event); - - $em->flush(); - // TODO: send mqtt event (?) - + // response return $res->getReturnResponse(); } - protected function updateVehicleBattery(JobOrder $jo) + public function getPromos(Request $req, RiderAPIHandlerInterface $rapi_handler) { - // check if new battery - if (($jo->getServiceType() != ServiceType::BATTERY_REPLACEMENT_NEW) || - ($jo->getServiceType() != CMBServiceType::BATTERY_REPLACEMENT_NEW)) - return; + $res = new APIResult(); - // customer vehicle - $cv = $jo->getCustomerVehicle(); - if ($cv == null) - return; + $data = $rapi_handler->getPromos($req); - // invoice - $invoice = $jo->getInvoice(); - if ($invoice == null) - return; - - // invoice items - $items = $invoice->getItems(); - if (count($items) <= 0) - return; - - // get first battery from invoice - $battery = null; - foreach ($items as $item) + if (isset($data['error'])) { - $battery = $item->getBattery(); - if ($battery != null) - break; + $message = $data['error']; + + $res->setError(true) + ->setErrorMessage($message); + } + else + { + $res->setData($data); } - // no battery in order - if ($battery == null) - return; - - // warranty expiration - $warr_months = 0; - $warr = $jo->getWarrantyClass(); - if ($warr == WarrantyClass::WTY_PRIVATE) - $warr_months = $battery->getWarrantyPrivate(); - else if ($warr == WarrantyClass::WTY_COMMERCIAL) - $warr_months = $battery->getWarrantyCommercial(); - else if ($warr == WarrantyClass::WTY_TNV) - $warr_months = 12; - - $warr_date = new DateTime(); - $warr_date->add(new DateInterval('P' . $warr_months . 'M')); - - // update customer vehicle battery - $cv->setCurrentBattery($battery) - ->setHasMotoliteBattery(true) - ->setWarrantyExpiration($warr_date); + // response + return $res->getReturnResponse(); } + public function getBatteries(Request $req, RiderAPIHandlerInterface $rapi_handler) + { + $res = new APIResult(); + + $data = $rapi_handler->getBatteries($req); + + if (isset($data['error'])) + { + $message = $data['error']; + + $res->setError(true) + ->setErrorMessage($message); + } + else + { + $res->setData($data); + } + + // response + return $res->getReturnResponse(); + } + + public function changeService(Request $req, RiderAPIHandlerInterface $rapi_handler) + { + $res = new APIResult(); + + $data = $rapi_handler->changeService($req); + + if (isset($data['error'])) + { + $message = $data['error']; + + $res->setError(true) + ->setErrorMessage($message); + } + else + { + $res->setData($data); + } + + // response + return $res->getReturnResponse(); + } } diff --git a/src/Service/JobOrderHandler/CMBJobOrderHandler.php b/src/Service/JobOrderHandler/CMBJobOrderHandler.php index 00a1ea49..234d968f 100644 --- a/src/Service/JobOrderHandler/CMBJobOrderHandler.php +++ b/src/Service/JobOrderHandler/CMBJobOrderHandler.php @@ -921,25 +921,29 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface else $date_purchase = $obj->getDateFulfill(); - $plate_number = $this->wh->cleanPlateNumber($obj->getCustomerVehicle()->getPlateNumber()); - - $batt_list = array(); - $invoice = $obj->getInvoice(); - if (!empty($invoice)) + // validate plate number + // $plate_number = $this->wh->cleanPlateNumber($jo->getCustomerVehicle()->getPlateNumber()); + $plate_number = Warranty::cleanPlateNumber($obj->getCustomerVehicle()->getPlateNumber()); + if ($plate_number != false) { - // get battery - $invoice_items = $invoice->getItems(); - foreach ($invoice_items as $item) + $batt_list = array(); + $invoice = $obj->getInvoice(); + if (!empty($invoice)) { - $battery = $item->getBattery(); - if ($battery != null) + // get battery + $invoice_items = $invoice->getItems(); + foreach ($invoice_items as $item) { - $batt_list[] = $item->getBattery(); + $battery = $item->getBattery(); + if ($battery != null) + { + $batt_list[] = $item->getBattery(); + } } } - } - $this->wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class); + $this->wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class); + } } } } @@ -2261,6 +2265,57 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface return null; } + public function updateVehicleBattery(JobOrder $jo) + { + // check if new battery + if ($jo->getServiceType() != CMBServiceType::BATTERY_REPLACEMENT_NEW) + return; + + // customer vehicle + $cv = $jo->getCustomerVehicle(); + if ($cv == null) + return; + + // invoice + $invoice = $jo->getInvoice(); + if ($invoice == null) + return; + + // invoice items + $items = $invoice->getItems(); + if (count($items) <= 0) + return; + + // get first battery from invoice + $battery = null; + foreach ($items as $item) + { + $battery = $item->getBattery(); + if ($battery != null) + break; + } + + // no battery in order + if ($battery == null) + return; + + // warranty expiration + // use GetWarrantyPrivate for passenger warranty + $warr = $jo->getWarrantyClass(); + if ($warr == CMBWarrantyClass::WTY_PASSENGER) + $warr_months = $battery->getWarrantyPrivate(); + else if ($warr == CMBWarrantyClass::WTY_COMMERCIAL) + $warr_months = $battery->getWarrantyCommercial(); + + $warr_date = new DateTime(); + $warr_date->add(new DateInterval('P' . $warr_months . 'M')); + + // update customer vehicle battery + $cv->setCurrentBattery($battery) + ->setHasMotoliteBattery(true) + ->setWarrantyExpiration($warr_date); + } + public function getOtherParameters() { // get riders for dropdown @@ -2269,7 +2324,6 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface return $params; } - protected function fillDropdownParameters(&$params) { $em = $this->em; @@ -2449,57 +2503,6 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface ]; } - protected function updateVehicleBattery(JobOrder $jo) - { - // check if new battery - if ($jo->getServiceType() != CMBServiceType::BATTERY_REPLACEMENT_NEW) - return; - - // customer vehicle - $cv = $jo->getCustomerVehicle(); - if ($cv == null) - return; - - // invoice - $invoice = $jo->getInvoice(); - if ($invoice == null) - return; - - // invoice items - $items = $invoice->getItems(); - if (count($items) <= 0) - return; - - // get first battery from invoice - $battery = null; - foreach ($items as $item) - { - $battery = $item->getBattery(); - if ($battery != null) - break; - } - - // no battery in order - if ($battery == null) - return; - - // warranty expiration - // use GetWarrantyPrivate for passenger warranty - $warr = $jo->getWarrantyClass(); - if ($warr == CMBWarrantyClass::WTY_PASSENGER) - $warr_months = $battery->getWarrantyPrivate(); - else if ($warr == CMBWarrantyClass::WTY_COMMERCIAL) - $warr_months = $battery->getWarrantyCommercial(); - - $warr_date = new DateTime(); - $warr_date->add(new DateInterval('P' . $warr_months . 'M')); - - // update customer vehicle battery - $cv->setCurrentBattery($battery) - ->setHasMotoliteBattery(true) - ->setWarrantyExpiration($warr_date); - } - // TODO: re-enable search, figure out how to group the orWhere filters into one, so can execute that plus the pending filter // check if datatable filter is present and append to query protected function setQueryFilters($datatable, &$query, $qb, $hubs, $tier, $status) diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index d04bcdff..f0d87fbe 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -723,27 +723,30 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface else $date_purchase = $obj->getDateFulfill(); - $plate_number = $this->wh->cleanPlateNumber($obj->getCustomerVehicle()->getPlateNumber()); - - $batt_list = array(); - $invoice = $obj->getInvoice(); - if (!empty($invoice)) + // validate plate number + // $plate_number = $this->wh->cleanPlateNumber($jo->getCustomerVehicle()->getPlateNumber()); + $plate_number = Warranty::cleanPlateNumber($obj->getCustomerVehicle()->getPlateNumber()); + if ($plate_number != false) { - // get battery - $invoice_items = $invoice->getItems(); - foreach ($invoice_items as $item) + $batt_list = array(); + $invoice = $obj->getInvoice(); + if (!empty($invoice)) { - $battery = $item->getBattery(); - if ($battery != null) + // get battery + $invoice_items = $invoice->getItems(); + foreach ($invoice_items as $item) { - $batt_list[] = $item->getBattery(); + $battery = $item->getBattery(); + if ($battery != null) + { + $batt_list[] = $item->getBattery(); + } } } + + $this->wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class); } - - $this->wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class); } - } } @@ -2220,6 +2223,59 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface return $params; } + public function updateVehicleBattery(JobOrder $jo) + { + // check if new battery + if ($jo->getServiceType() != ServiceType::BATTERY_REPLACEMENT_NEW) + return; + + // customer vehicle + $cv = $jo->getCustomerVehicle(); + if ($cv == null) + return; + + // invoice + $invoice = $jo->getInvoice(); + if ($invoice == null) + return; + + // invoice items + $items = $invoice->getItems(); + if (count($items) <= 0) + return; + + // get first battery from invoice + $battery = null; + foreach ($items as $item) + { + $battery = $item->getBattery(); + if ($battery != null) + break; + } + + // no battery in order + if ($battery == null) + return; + + // warranty expiration + $warr = $jo->getWarrantyClass(); + $warr_months = 0; + if ($warr == WarrantyClass::WTY_PRIVATE) + $warr_months = $battery->getWarrantyPrivate(); + else if ($warr == WarrantyClass::WTY_COMMERCIAL) + $warr_months = $battery->getWarrantyCommercial(); + else if ($warr == WarrantyClass::WTY_TNV) + $warr_months = 12; + + $warr_date = new DateTime(); + $warr_date->add(new DateInterval('P' . $warr_months . 'M')); + + // update customer vehicle battery + $cv->setCurrentBattery($battery) + ->setHasMotoliteBattery(true) + ->setWarrantyExpiration($warr_date); + } + protected function fillDropdownParameters(&$params) { $em = $this->em; @@ -2399,58 +2455,6 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ]; } - protected function updateVehicleBattery(JobOrder $jo) - { - // check if new battery - if ($jo->getServiceType() != ServiceType::BATTERY_REPLACEMENT_NEW) - return; - - // customer vehicle - $cv = $jo->getCustomerVehicle(); - if ($cv == null) - return; - - // invoice - $invoice = $jo->getInvoice(); - if ($invoice == null) - return; - - // invoice items - $items = $invoice->getItems(); - if (count($items) <= 0) - return; - - // get first battery from invoice - $battery = null; - foreach ($items as $item) - { - $battery = $item->getBattery(); - if ($battery != null) - break; - } - - // no battery in order - if ($battery == null) - return; - - // warranty expiration - $warr = $jo->getWarrantyClass(); - if ($warr == WarrantyClass::WTY_PRIVATE) - $warr_months = $battery->getWarrantyPrivate(); - else if ($warr == WarrantyClass::WTY_COMMERCIAL) - $warr_months = $battery->getWarrantyCommercial(); - else if ($warr == WarrantyClass::WTY_TNV) - $warr_months = 12; - - $warr_date = new DateTime(); - $warr_date->add(new DateInterval('P' . $warr_months . 'M')); - - // update customer vehicle battery - $cv->setCurrentBattery($battery) - ->setHasMotoliteBattery(true) - ->setWarrantyExpiration($warr_date); - } - // TODO: re-enable search, figure out how to group the orWhere filters into one, so can execute that plus the pending filter // check if datatable filter is present and append to query protected function setQueryFilters($datatable, &$query, $qb, $hubs, $tier, $status) diff --git a/src/Service/JobOrderHandlerInterface.php b/src/Service/JobOrderHandlerInterface.php index be1c583c..29939cb5 100644 --- a/src/Service/JobOrderHandlerInterface.php +++ b/src/Service/JobOrderHandlerInterface.php @@ -8,6 +8,8 @@ use App\Service\MQTTClient; use App\Service\APNSClient; use App\Service\MapTools; +use App\Entity\JobOrder; + interface JobOrderHandlerInterface { // TODO: event sending has been moved to rider assignment handler for cmb. Might need @@ -90,4 +92,7 @@ interface JobOrderHandlerInterface // get template to display public function getTwigTemplate(string $id); + + // update customer vehicle battery warranty info + public function updateVehicleBattery(JobOrder $jo); } diff --git a/src/Service/RiderAPIHandler/CMBRiderAPIHandler.php b/src/Service/RiderAPIHandler/CMBRiderAPIHandler.php new file mode 100644 index 00000000..fa416e27 --- /dev/null +++ b/src/Service/RiderAPIHandler/CMBRiderAPIHandler.php @@ -0,0 +1,928 @@ +em = $em; + $this->redis = $redis; + $this->ef = $ef; + $this->rcache = $rcache; + $this->country_code = $country_code; + $this->mclient = $mclient; + $this->wh = $wh; + $this->jo_handler = $jo_handler; + $this->ic = $ic; + + // 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 + // when a rider logs out, we remove the rider assigned to the device + $this->session = null; + } + + public function register(Request $req) + { + // confirm parameters + $required_params = [ + 'phone_number', + 'device_push_id' + ]; + + $missing = $this->checkMissingParameters($req, $required_params); + if (count($missing) > 0) + { + $params = implode(', ', $missing); + $data = [ + 'error' => 'Missing parameter(s): ' . $params + ]; + return $data; + } + + // retry until we get a unique id + while (true) + { + try + { + // instantiate session + $sess = new RiderSession(); + $sess->setPhoneNumber($req->request->get('phone_number')) + ->setDevicePushID($req->request->get('device_push_id')); + + // reopen in case we get an exception + if (!$this->em->isOpen()) + { + $this->em = $this->em->create( + $this->em->getConnection(), + $this->em->getConfiguration() + ); + } + + // save + $this->em->persist($sess); + $this->em->flush(); + + // create redis entry for the session + $redis_client = $this->redis->getRedisClient(); + $redis_key = 'rider.id.' . $sess->getID(); + error_log('redis_key: ' . $redis_key); + $redis_client->set($redis_key, ''); + } + catch (DBALException $e) + { + error_log($e->getMessage()); + // delay one second and try again + sleep(1); + continue; + } + + break; + } + + // return data + $data = [ + 'session_id' => $sess->getID() + ]; + + return $data; + } + + public function login(Request $req) + { + $required_params = [ + 'user', + 'pass', + ]; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // check if session has a rider already + if ($this->session->hasRider()) + { + $data = [ + 'error' => 'Another rider is already logged in. Please logout first.' + ]; + return $data; + } + + // look for rider with username + $rider = $this->em->getRepository(Rider::class)->findOneBy(['username' => $req->request->get('user')]); + if ($rider == null) + { + $data = [ + 'error' => 'Invalid username or password.' + ]; + return $data; + } + + // check if rider password is correct + $encoder = $this->ef->getEncoder(new User()); + if (!$encoder->isPasswordValid($rider->getPassword(), $req->request->get('pass'), '')) + { + $data = [ + 'error' => 'Invalid username or password.' + ]; + return $data; + } + + // assign rider to session + $this->session->setRider($rider); + + $rider->setAvailable(true); + + $rider_id = $rider->getID(); + // cache rider location (default to hub) + // TODO: figure out longitude / latitude default + $this->rcache->addActiveRider($rider_id, 0, 0); + + // TODO: log rider logging in + + $this->em->flush(); + + // update redis rider.id. with the rider id + $redis_client = $this->redis->getRedisClient(); + $redis_key = 'rider.id.' . $this->session->getID(); + $rider_id = $rider->getID(); + + $redis_client->set($redis_key, $rider_id); + + $hub = $rider->getHub(); + if ($hub == null) + $hub_data = null; + else + { + $coord = $hub->getCoordinates(); + $hub_data = [ + 'id' => $hub->getID(), + 'name' => $hub->getName(), + 'branch' => $hub->getBranch(), + 'longitude' => $coord->getLongitude(), + 'latitude' => $coord->getLatitude(), + 'contact_nums' => $hub->getContactNumbers(), + ]; + } + + // data + $data = [ + 'hub' => $hub_data, + 'rider_id' => $rider_id, + ]; + + return $data; + } + + public function logout(Request $req) + { + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // make rider unavailable + $rider = $this->session->getRider(); + $rider->setAvailable(false); + + // remove from cache + $this->rcache->removeActiveRider($rider->getID()); + + // remove rider from session + $this->session->setRider(null); + + // TODO: log rider logging out + + $this->em->flush(); + + return $data; + } + + public function getJobOrder(Request $req) + { + // get the job order of the rider assigned to this session + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // are we logged in? + if (!$this->session->hasRider()) + { + $data = [ + 'error' => 'No logged in rider.' + ]; + return $data; + } + + $rider = $this->session->getRider(); + + // do we have a job order? + $jo = $rider->getActiveJobOrder(); + if ($jo == null) + { + $data = [ + 'job_order' => null + ]; + } + else + { + $coord = $jo->getCoordinates(); + $cust = $jo->getCustomer(); + $cv = $jo->getCustomerVehicle(); + $v = $cv->getVehicle(); + $inv = $jo->getInvoice(); + $promo = $inv->getPromo(); + + // invoice items + $inv_items = []; + foreach ($inv->getItems() as $item) + { + $item_batt = $item->getBattery(); + if ($item_batt == null) + $batt_id = null; + else + $batt_id = $item_batt->getID(); + + $inv_items[] = [ + 'id' => $item->getID(), + 'title' => $item->getTitle(), + 'qty' => $item->getQuantity(), + 'price' => $item->getPrice(), + 'batt_id' => $batt_id, + ]; + } + + // promo + if ($promo != null) + { + $promo_data = [ + 'id' => $promo->getID(), + 'name' => $promo->getName(), + 'code' => $promo->getCode(), + 'discount_rate' => $promo->getDiscountRate(), + 'discount_apply' => $promo->getDiscountApply(), + ]; + } + else + { + $promo_data = null; + } + + $trade_in_type = $jo->getTradeInType(); + if (empty($trade_in_type)) + $trade_in_type = 'none'; + + $data = [ + 'job_order' => [ + 'id' => $jo->getID(), + 'service_type' => $jo->getServiceType(), + 'date_schedule' => $jo->getDateSchedule()->format('Ymd H:i:s'), + 'longitude' => $coord->getLongitude(), + 'latitude' => $coord->getLatitude(), + 'status' => $jo->getStatus(), + 'customer' => [ + 'title' => $cust->getTitle(), + 'first_name' => $cust->getFirstName(), + 'last_name' => $cust->getLastName(), + 'phone_mobile' => $this->country_code . $cust->getPhoneMobile(), + ], + 'vehicle' => [ + 'manufacturer' => $v->getManufacturer()->getName(), + 'make' => $v->getMake(), + 'model' => $cv->getModelYear(), + 'plate_number' => $cv->getPlateNumber(), + 'color' => $cv->getColor(), + ], + 'or_num' => $jo->getORNum(), + 'or_name' => $jo->getORName(), + 'delivery_instructions' => $jo->getDeliveryInstructions(), + 'delivery_address' => $jo->getDeliveryAddress(), + 'landmark' => $jo->getLandmark(), + 'invoice' => [ + 'discount' => $inv->getDiscount(), + 'trade_in' => $inv->getTradeIn(), + 'total_price' => $inv->getTotalPrice(), + 'vat' => $inv->getVat(), + 'items' => $inv_items, + ], + 'mode_of_payment' => $jo->getModeOfPayment(), + 'trade_in_type' => $trade_in_type, + 'promo' => $promo_data, + // TODO: load the actual + 'has_warranty_doc' => false, + 'flag_coolant' => $jo->hasCoolant(), + 'has_motolite' => $cv->hasMotoliteBattery(), + ] + ]; + } + + return $data; + } + + public function acceptJobOrder(Request $req) + { + $required_params = ['jo_id']; + $data = $this->checkJO($req, $required_params, $jo); + if (isset($data['error'])) + return $data; + + // TODO: refactor this into a jo handler class, so we don't have to repeat for control center + + // set jo status to in transit + $jo->setStatus(JOStatus::IN_TRANSIT); + + // TODO: send mqtt event (?) + + // add event log + $rider = $this->session->getRider(); + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::RIDER_ACCEPT) + ->setJobOrder($jo) + ->setRider($rider); + $this->em->persist($event); + + $this->em->flush(); + + return $data; + } + + public function cancelJobOrder(Request $req) + { + $required_params = ['jo_id']; + $data = $this->checkJO($req, $required_params, $jo); + if (isset($data['error'])) + return $data; + + // $jo->cancel("rider cancelled"); + // requeue it, instead of cancelling it + $jo->requeue(); + + // add event log + $rider = $this->session->getRider(); + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::REQUEUE) + ->setJobOrder($jo) + ->setRider($rider); + $this->em->persist($event); + + $this->em->flush(); + + // send mqtt event + // send outlet assign since order should go back to hub and await reassignment to another rider + $payload = [ + 'event' => 'outlet_assign', + 'jo_id' => $jo->getID(), + ]; + $this->mclient->sendEvent($jo, $payload); + + return $data; + } + + public function arrive(Request $req) + { + $required_params = ['jo_id']; + $data = $this->checkJO($req, $required_params, $jo); + if (isset($data['error'])) + return $data; + + // TODO: refactor this into a jo handler class, so we don't have to repeat for control center + + // set jo status to in progress + $jo->setStatus(JOStatus::IN_PROGRESS); + + // add event log + $rider = $this->session->getRider(); + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::RIDER_ARRIVE) + ->setJobOrder($jo) + ->setRider($rider); + $this->em->persist($event); + + $this->em->flush(); + + // send mqtt event + $rider = $this->session->getRider(); + $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/assets/images/user.gif'; + if ($rider->getImageFile() != null) + $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/uploads/' . $rider->getImageFile(); + + $payload = [ + 'event' => 'driver_arrived', + 'jo_id' => $jo->getID(), + 'driver_image' => $image_url, + 'driver_name' => $rider->getFullName(), + 'driver_id' => $rider->getID(), + ]; + $this->mclient->sendEvent($jo, $payload); + + return $data; + } + + public function hubArrive(Request $req) + { + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // are we logged in? + if (!$this->session->hasRider()) + { + $data = [ + 'error' => 'No logged in rider.' + ]; + return $data; + } + + // TODO: tag rider as available + + $this->em->flush(); + + return $data; + } + + public function payment(Request $req) + { + $required_params = ['jo_id']; + $data = $this->checkJO($req, $required_params, $jo); + if (isset($data['error'])) + return $data; + + // set invoice to paid + $jo->getInvoice()->setStatus(InvoiceStatus::PAID); + + /* + // set jo status to fulfilled + $jo->setStatus(JOStatus::FULFILLED); + */ + $jo->fulfill(); + + // add event log + $rider = $this->session->getRider(); + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::FULFILL) + ->setJobOrder($jo) + ->setRider($rider); + $this->em->persist($event); + + // TODO: tag rider as unavailable + + // save to customer vehicle battery record + $this->jo_handler->updateVehicleBattery($jo); + + $this->em->flush(); + + // create warranty + if ($jo->getServiceType() == CMBServiceType::BATTERY_REPLACEMENT_NEW) + { + $serial = null; + $warranty_class = $jo->getWarrantyClass(); + $first_name = $jo->getCustomer()->getFirstName(); + $last_name = $jo->getCustomer()->getLastName(); + $mobile_number = $jo->getCustomer()->getPhoneMobile(); + + // check if date fulfilled is null + if ($jo->getDateFulfill() == null) + $date_purchase = $jo->getDateCreate(); + else + $date_purchase = $jo->getDateFulfill(); + + // validate plate number + // $plate_number = $this->wh->cleanPlateNumber($jo->getCustomerVehicle()->getPlateNumber()); + $plate_number = Warranty::cleanPlateNumber($jo->getCustomerVehicle()->getPlateNumber()); + if ($plate_number != false) + { + $batt_list = array(); + $invoice = $jo->getInvoice(); + if (!empty($invoice)) + { + // get battery + $invoice_items = $invoice->getItems(); + foreach ($invoice_items as $item) + { + $battery = $item->getBattery(); + if ($battery != null) + { + $batt_list[] = $item->getBattery(); + } + } + } + + $this->wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class); + } + } + + // send mqtt event (fulfilled) + $rider = $this->session->getRider(); + $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/assets/images/user.gif'; + if ($rider->getImageFile() != null) + $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/uploads/' . $rider->getImageFile(); + + $payload = [ + 'event' => 'fulfilled', + 'jo_id' => $jo->getID(), + 'driver_image' => $image_url, + 'driver_name' => $rider->getFullName(), + 'driver_id' => $rider->getID(), + ]; + $this->mclient->sendEvent($jo, $payload); + + return $data; + } + + public function available(Request $req) + { + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // make rider available + $this->session->getRider()->setAvailable(true); + + // TODO: log rider available + $this->em->flush(); + + return $data; + } + + public function getPromos(Request $req) + { + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + $promos = $this->em->getRepository(Promo::class)->findAll(); + + $promo_data = []; + foreach ($promos as $promo) + { + $promo_data[] = [ + 'id' => $promo->getID(), + 'name' => $promo->getName(), + 'code' => $promo->getCode(), + ]; + } + + $data = [ + 'promos' => $promo_data, + ]; + + return $data; + } + + public function getBatteries(Request $req) + { + // get batteries, models, and sizes + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + $batts = $this->em->getRepository(Battery::class)->findAll(); + $models = $this->em->getRepository(BatteryModel::class)->findAll(); + $sizes = $this->em->getRepository(BatterySize::class)->findAll(); + + $batt_data = []; + foreach ($batts as $batt) + { + $batt_data[] = [ + 'id' => $batt->getID(), + 'model_id' => $batt->getModel()->getID(), + 'size_id' => $batt->getSize()->getID(), + 'sell_price' => $batt->getSellingPrice(), + ]; + } + + $model_data = []; + foreach ($models as $model) + { + $model_data[] = [ + 'id' => $model->getID(), + 'name' => $model->getName(), + ]; + } + + $size_data = []; + foreach ($sizes as $size) + { + $size_data[] = [ + 'id' => $size->getID(), + 'name' => $size->getName(), + ]; + } + + $data = [ + 'batteries' => $batt_data, + 'models' => $model_data, + 'sizes' => $size_data, + ]; + + return $data; + } + + public function changeService(Request $req) + { + $this->debugRequest($req); + + // allow rider to change service, promo, battery and trade-in options + $required_params = ['jo_id', 'stype_id', 'promo_id']; + $data = $this->checkJO($req, $required_params, $jo); + if (isset($data['error'])) + return $data; + + // check service type + $stype_id = $req->request->get('stype_id'); + if (!CMBServiceType::validate($stype_id)) + { + $data = [ + 'error' => 'Invalid service type - ' . $stype_id + ]; + return $data; + } + + // check promo id + $promo_id = $req->request->get('promo_id'); + // no promo + if ($promo_id == 0) + $promo = null; + else + { + $promo = $this->em->getRepository(Promo::class)->find($promo_id); + if ($promo == null) + { + $data = [ + 'error' => 'Invalid promo id - ' . $promo_id + ]; + return $data; + } + } + + // check or number + $or_num = $req->request->get('or_num'); + if ($or_num != null) + $jo->setORNum($or_num); + + // coolant + $flag_coolant = $req->request->get('flag_coolant', 'false'); + if ($flag_coolant == 'true') + $jo->setHasCoolant(true); + else + $jo->setHasCoolant(false); + + // has motolite battery + $cv = $jo->getCustomerVehicle(); + $has_motolite = $req->request->get('has_motolite', 'false'); + if ($has_motolite == 'true') + $cv->setHasMotoliteBattery(true); + else + $cv->setHasMotoliteBattery(false); + $this->em->persist($cv); + + // check battery id + $batt_id = $req->request->get('batt_id', null); + // no battery + if ($batt_id == 0 || $batt_id == null) + $battery = null; + else + { + $battery = $this->em->getRepository(Battery::class)->find($batt_id); + if ($battery == null) + { + $data = [ + 'error' => 'Invalid battery id - ' . $batt_id + ]; + return $data; + } + } + + // check trade in + $trade_in = $req->request->get('trade_in'); + if (!CMBTradeInType::validate($trade_in)) + $trade_in = null; + + // check mode of payment + $mode = $req->request->get('mode_of_payment'); + if (!ModeOfPayment::validate($mode)) + $mode = ModeOfPayment::CASH; + $jo->setModeOfPayment($mode); + + // generate new invoice + $crit = new InvoiceCriteria(); + $crit->setServiceType($stype_id); + $crit->setCustomerVehicle($cv); + $crit->setHasCoolant($jo->hasCoolant()); + + if ($promo != null) + $crit->addPromo($promo); + + if ($battery != null) + { + $crit->addEntry($battery, $trade_in, 1); + error_log('adding entry for battery - ' . $battery->getID()); + } + + $invoice = $this->ic->generateInvoice($crit); + + // remove previous invoice + $old_invoice = $jo->getInvoice(); + $this->em->remove($old_invoice); + $this->em->flush(); + + // save job order + $jo->setServiceType($stype_id); + + // save invoice + $jo->setInvoice($invoice); + $this->em->persist($invoice); + + // add event log + $rider = $this->session->getRider(); + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::RIDER_EDIT) + ->setJobOrder($jo) + ->setRider($rider); + $this->em->persist($event); + + $this->em->flush(); + // TODO: send mqtt event (?) + + return $data; + } + + protected function checkMissingParameters(Request $req, $params = []) + { + $missing = []; + + // check if parameters are there + foreach ($params as $param) + { + if ($req->getMethod() == 'GET') + { + $check = $req->query->get($param); + if ($check == null) + $missing[] = $param; + } + else if ($req->getMethod() == 'POST') + { + $check = $req->request->get($param); + if ($check == null) + $missing[] = $param; + } + else + return $params; + } + + return $missing; + } + + protected function checkParamsAndKey(Request $req, $params) + { + $data = []; + + // check for api_key in query string + $api_key = $req->query->get('api_key'); + if (empty($api_key)) + { + $data = [ + 'error' => 'Missing API key' + ]; + return $data; + } + + // check missing parameters + $missing = $this->checkMissingParameters($req, $params); + if (count($missing) > 0) + { + $miss_string = implode(', ', $missing); + $data = [ + 'error' => 'Missing parameter(s): ' . $miss_string + ]; + return $data; + } + + // check api key + $sess = $this->checkAPIKey($req->query->get('api_key')); + if ($sess == null) + { + $data = [ + 'error' => 'Invalid API Key' + ]; + return $data; + } + + // store session + $this->session = $sess; + + return $data; + } + + protected function checkAPIKey($api_key) + { + // find the api key (session id) + $session = $this->em->getRepository(RiderSession::class)->find($api_key); + if ($session == null) + return null; + + return $session; + } + + protected function checkJO(Request $req, $required_params, &$jo = null) + { + // set jo status to in transit + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // are we logged in? + if (!$this->session->hasRider()) + { + $data = [ + 'error' => 'No logged in rider.' + ]; + return $data; + } + + $rider = $this->session->getRider(); + + // check if we have an active JO + $jo = $rider->getActiveJobOrder(); + if ($jo == null) + { + $data = [ + 'error' => 'No active job order.' + ]; + return $data; + } + + // check if the jo_id sent is the same as our active jo + if ($req->request->get('jo_id') != $jo->getID()) + { + $data = [ + 'error' => 'Job order selected is not active job order.' + ]; + return $data; + } + + return $data; + } + + protected function debugRequest(Request $req) + { + $all = $req->request->all(); + error_log(print_r($all, true)); + } +} diff --git a/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php b/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php new file mode 100644 index 00000000..a9ffc1b5 --- /dev/null +++ b/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php @@ -0,0 +1,923 @@ +em = $em; + $this->redis = $redis; + $this->ef = $ef; + $this->rcache = $rcache; + $this->country_code = $country_code; + $this->mclient = $mclient; + $this->wh = $wh; + $this->jo_handler = $jo_handler; + $this->ic = $ic; + + // 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 + // when a rider logs out, we remove the rider assigned to the device + $this->session = null; + } + + public function register(Request $req) + { + // confirm parameters + $required_params = [ + 'phone_number', + 'device_push_id' + ]; + + $missing = $this->checkMissingParameters($req, $required_params); + if (count($missing) > 0) + { + $params = implode(', ', $missing); + $data = [ + 'error' => 'Missing parameter(s): ' . $params + ]; + return $data; + } + + // retry until we get a unique id + while (true) + { + try + { + // instantiate session + $sess = new RiderSession(); + $sess->setPhoneNumber($req->request->get('phone_number')) + ->setDevicePushID($req->request->get('device_push_id')); + + // reopen in case we get an exception + if (!$this->em->isOpen()) + { + $this->em = $this->em->create( + $this->em->getConnection(), + $this->em->getConfiguration() + ); + } + + // save + $this->em->persist($sess); + $this->em->flush(); + + // create redis entry for the session + $redis_client = $this->redis->getRedisClient(); + $redis_key = 'rider.id.' . $sess->getID(); + error_log('redis_key: ' . $redis_key); + $redis_client->set($redis_key, ''); + } + catch (DBALException $e) + { + error_log($e->getMessage()); + // delay one second and try again + sleep(1); + continue; + } + + break; + } + + // return data + $data = [ + 'session_id' => $sess->getID() + ]; + + return $data; + } + + public function login(Request $req) + { + $required_params = [ + 'user', + 'pass', + ]; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // check if session has a rider already + if ($this->session->hasRider()) + { + $data = [ + 'error' => 'Another rider is already logged in. Please logout first.' + ]; + return $data; + } + + // look for rider with username + $rider = $this->em->getRepository(Rider::class)->findOneBy(['username' => $req->request->get('user')]); + if ($rider == null) + { + $data = [ + 'error' => 'Invalid username or password.' + ]; + return $data; + } + + // check if rider password is correct + $encoder = $this->ef->getEncoder(new User()); + if (!$encoder->isPasswordValid($rider->getPassword(), $req->request->get('pass'), '')) + { + $data = [ + 'error' => 'Invalid username or password.' + ]; + return $data; + } + + // assign rider to session + $this->session->setRider($rider); + + $rider->setAvailable(true); + + $rider_id = $rider->getID(); + // cache rider location (default to hub) + // TODO: figure out longitude / latitude default + $this->rcache->addActiveRider($rider_id, 0, 0); + + // TODO: log rider logging in + + $this->em->flush(); + + // update redis rider.id. with the rider id + $redis_client = $this->redis->getRedisClient(); + $redis_key = 'rider.id.' . $this->session->getID(); + $rider_id = $rider->getID(); + + $redis_client->set($redis_key, $rider_id); + + $hub = $rider->getHub(); + if ($hub == null) + $hub_data = null; + else + { + $coord = $hub->getCoordinates(); + $hub_data = [ + 'id' => $hub->getID(), + 'name' => $hub->getName(), + 'branch' => $hub->getBranch(), + 'longitude' => $coord->getLongitude(), + 'latitude' => $coord->getLatitude(), + 'contact_nums' => $hub->getContactNumbers(), + ]; + } + + // data + $data = [ + 'hub' => $hub_data, + 'rider_id' => $rider_id, + ]; + + return $data; + } + + public function logout(Request $req) + { + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // make rider unavailable + $rider = $this->session->getRider(); + $rider->setAvailable(false); + + // remove from cache + $this->rcache->removeActiveRider($rider->getID()); + + // remove rider from session + $this->session->setRider(null); + + // TODO: log rider logging out + + $this->em->flush(); + + return $data; + } + + public function getJobOrder(Request $req) + { + // get the job order of the rider assigned to this session + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // are we logged in? + if (!$this->session->hasRider()) + { + $data = [ + 'error' => 'No logged in rider.' + ]; + return $data; + } + + $rider = $this->session->getRider(); + + // do we have a job order? + $jo = $rider->getActiveJobOrder(); + if ($jo == null) + { + $data = [ + 'job_order' => null + ]; + } + else + { + $coord = $jo->getCoordinates(); + $cust = $jo->getCustomer(); + $cv = $jo->getCustomerVehicle(); + $v = $cv->getVehicle(); + $inv = $jo->getInvoice(); + $promo = $inv->getPromo(); + + // invoice items + $inv_items = []; + foreach ($inv->getItems() as $item) + { + $item_batt = $item->getBattery(); + if ($item_batt == null) + $batt_id = null; + else + $batt_id = $item_batt->getID(); + + $inv_items[] = [ + 'id' => $item->getID(), + 'title' => $item->getTitle(), + 'qty' => $item->getQuantity(), + 'price' => $item->getPrice(), + 'batt_id' => $batt_id, + ]; + } + + // promo + if ($promo != null) + { + $promo_data = [ + 'id' => $promo->getID(), + 'name' => $promo->getName(), + 'code' => $promo->getCode(), + 'discount_rate' => $promo->getDiscountRate(), + 'discount_apply' => $promo->getDiscountApply(), + ]; + } + else + { + $promo_data = null; + } + + $trade_in_type = $jo->getTradeInType(); + if (empty($trade_in_type)) + $trade_in_type = 'none'; + + $data = [ + 'job_order' => [ + 'id' => $jo->getID(), + 'service_type' => $jo->getServiceType(), + 'date_schedule' => $jo->getDateSchedule()->format('Ymd H:i:s'), + 'longitude' => $coord->getLongitude(), + 'latitude' => $coord->getLatitude(), + 'status' => $jo->getStatus(), + 'customer' => [ + 'title' => $cust->getTitle(), + 'first_name' => $cust->getFirstName(), + 'last_name' => $cust->getLastName(), + 'phone_mobile' => $this->country_code . $cust->getPhoneMobile(), + ], + 'vehicle' => [ + 'manufacturer' => $v->getManufacturer()->getName(), + 'make' => $v->getMake(), + 'model' => $cv->getModelYear(), + 'plate_number' => $cv->getPlateNumber(), + 'color' => $cv->getColor(), + ], + 'or_num' => $jo->getORNum(), + 'or_name' => $jo->getORName(), + 'delivery_instructions' => $jo->getDeliveryInstructions(), + 'delivery_address' => $jo->getDeliveryAddress(), + 'landmark' => $jo->getLandmark(), + 'invoice' => [ + 'discount' => $inv->getDiscount(), + 'trade_in' => $inv->getTradeIn(), + 'total_price' => $inv->getTotalPrice(), + 'vat' => $inv->getVat(), + 'items' => $inv_items, + ], + 'mode_of_payment' => $jo->getModeOfPayment(), + 'trade_in_type' => $trade_in_type, + 'promo' => $promo_data, + // TODO: load the actual + 'has_warranty_doc' => false, + 'flag_coolant' => $jo->hasCoolant(), + 'has_motolite' => $cv->hasMotoliteBattery(), + ] + ]; + } + + return $data; + } + + public function acceptJobOrder(Request $req) + { + $required_params = ['jo_id']; + $data = $this->checkJO($req, $required_params, $jo); + if (isset($data['error'])) + return $data; + + // TODO: refactor this into a jo handler class, so we don't have to repeat for control center + + // set jo status to in transit + $jo->setStatus(JOStatus::IN_TRANSIT); + + // TODO: send mqtt event (?) + + // add event log + $rider = $this->session->getRider(); + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::RIDER_ACCEPT) + ->setJobOrder($jo) + ->setRider($rider); + $this->em->persist($event); + + $this->em->flush(); + + return $data; + } + + public function cancelJobOrder(Request $req) + { + $required_params = ['jo_id']; + $data = $this->checkJO($req, $required_params, $jo); + if (isset($data['error'])) + return $data; + + // $jo->cancel("rider cancelled"); + // requeue it, instead of cancelling it + $jo->requeue(); + + // add event log + $rider = $this->session->getRider(); + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::REQUEUE) + ->setJobOrder($jo) + ->setRider($rider); + $this->em->persist($event); + + $this->em->flush(); + + // send mqtt event + // send outlet assign since order should go back to hub and await reassignment to another rider + $payload = [ + 'event' => 'outlet_assign', + 'jo_id' => $jo->getID(), + ]; + $this->mclient->sendEvent($jo, $payload); + + return $data; + } + + public function arrive(Request $req) + { + $required_params = ['jo_id']; + $data = $this->checkJO($req, $required_params, $jo); + if (isset($data['error'])) + return $data; + + // TODO: refactor this into a jo handler class, so we don't have to repeat for control center + + // set jo status to in progress + $jo->setStatus(JOStatus::IN_PROGRESS); + + // add event log + $rider = $this->session->getRider(); + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::RIDER_ARRIVE) + ->setJobOrder($jo) + ->setRider($rider); + $this->em->persist($event); + + $this->em->flush(); + + // send mqtt event + $rider = $this->session->getRider(); + $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/assets/images/user.gif'; + if ($rider->getImageFile() != null) + $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/uploads/' . $rider->getImageFile(); + + $payload = [ + 'event' => 'driver_arrived', + 'jo_id' => $jo->getID(), + 'driver_image' => $image_url, + 'driver_name' => $rider->getFullName(), + 'driver_id' => $rider->getID(), + ]; + $this->mclient->sendEvent($jo, $payload); + + return $data; + } + + public function hubArrive(Request $req) + { + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // are we logged in? + if (!$this->session->hasRider()) + { + $data = [ + 'error' => 'No logged in rider.' + ]; + return $data; + } + + // TODO: tag rider as available + + $this->em->flush(); + + return $data; + } + + public function payment(Request $req) + { + $required_params = ['jo_id']; + $data = $this->checkJO($req, $required_params, $jo); + if (isset($data['error'])) + return $data; + + // set invoice to paid + $jo->getInvoice()->setStatus(InvoiceStatus::PAID); + + /* + // set jo status to fulfilled + $jo->setStatus(JOStatus::FULFILLED); + */ + $jo->fulfill(); + + // add event log + $rider = $this->session->getRider(); + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::FULFILL) + ->setJobOrder($jo) + ->setRider($rider); + $this->em->persist($event); + + // TODO: tag rider as unavailable + + // save to customer vehicle battery record + $this->jo_handler->updateVehicleBattery($jo); + + $this->em->flush(); + + // create warranty + if ($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) + { + $serial = null; + $warranty_class = $jo->getWarrantyClass(); + $first_name = $jo->getCustomer()->getFirstName(); + $last_name = $jo->getCustomer()->getLastName(); + $mobile_number = $jo->getCustomer()->getPhoneMobile(); + + // check if date fulfilled is null + if ($jo->getDateFulfill() == null) + $date_purchase = $jo->getDateCreate(); + else + $date_purchase = $jo->getDateFulfill(); + + $plate_number = $this->wh->cleanPlateNumber($jo->getCustomerVehicle()->getPlateNumber()); + + $batt_list = array(); + $invoice = $jo->getInvoice(); + if (!empty($invoice)) + { + // get battery + $invoice_items = $invoice->getItems(); + foreach ($invoice_items as $item) + { + $battery = $item->getBattery(); + if ($battery != null) + { + $batt_list[] = $item->getBattery(); + } + } + } + + $this->wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class); + } + + // send mqtt event (fulfilled) + $rider = $this->session->getRider(); + $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/assets/images/user.gif'; + if ($rider->getImageFile() != null) + $image_url = $req->getScheme() . '://' . $req->getHttpHost() . $req->getBasePath() . '/uploads/' . $rider->getImageFile(); + + $payload = [ + 'event' => 'fulfilled', + 'jo_id' => $jo->getID(), + 'driver_image' => $image_url, + 'driver_name' => $rider->getFullName(), + 'driver_id' => $rider->getID(), + ]; + $this->mclient->sendEvent($jo, $payload); + + return $data; + } + + public function available(Request $req) + { + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // make rider available + $this->session->getRider()->setAvailable(true); + + // TODO: log rider available + $this->em->flush(); + + return $data; + } + + public function getPromos(Request $req) + { + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + $promos = $this->em->getRepository(Promo::class)->findAll(); + + $promo_data = []; + foreach ($promos as $promo) + { + $promo_data[] = [ + 'id' => $promo->getID(), + 'name' => $promo->getName(), + 'code' => $promo->getCode(), + ]; + } + + $data = [ + 'promos' => $promo_data, + ]; + + return $data; + } + + public function getBatteries(Request $req) + { + // get batteries, models, and sizes + $required_params = []; + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + $batts = $this->em->getRepository(Battery::class)->findAll(); + $models = $this->em->getRepository(BatteryModel::class)->findAll(); + $sizes = $this->em->getRepository(BatterySize::class)->findAll(); + + $batt_data = []; + foreach ($batts as $batt) + { + $batt_data[] = [ + 'id' => $batt->getID(), + 'model_id' => $batt->getModel()->getID(), + 'size_id' => $batt->getSize()->getID(), + 'sell_price' => $batt->getSellingPrice(), + ]; + } + + $model_data = []; + foreach ($models as $model) + { + $model_data[] = [ + 'id' => $model->getID(), + 'name' => $model->getName(), + ]; + } + + $size_data = []; + foreach ($sizes as $size) + { + $size_data[] = [ + 'id' => $size->getID(), + 'name' => $size->getName(), + ]; + } + + $data = [ + 'batteries' => $batt_data, + 'models' => $model_data, + 'sizes' => $size_data, + ]; + + return $data; + } + + public function changeService(Request $req) + { + $this->debugRequest($req); + + // allow rider to change service, promo, battery and trade-in options + $required_params = ['jo_id', 'stype_id', 'promo_id']; + $data = $this->checkJO($req, $required_params, $jo); + if (isset($data['error'])) + return $data; + + // check service type + $stype_id = $req->request->get('stype_id'); + if (!ServiceType::validate($stype_id)) + { + $data = [ + 'error' => 'Invalid service type - ' . $stype_id + ]; + return $data; + } + + // check promo id + $promo_id = $req->request->get('promo_id'); + // no promo + if ($promo_id == 0) + $promo = null; + else + { + $promo = $this->em->getRepository(Promo::class)->find($promo_id); + if ($promo == null) + { + $data = [ + 'error' => 'Invalid promo id - ' . $promo_id + ]; + return $data; + } + } + + // check or number + $or_num = $req->request->get('or_num'); + if ($or_num != null) + $jo->setORNum($or_num); + + // coolant + $flag_coolant = $req->request->get('flag_coolant', 'false'); + if ($flag_coolant == 'true') + $jo->setHasCoolant(true); + else + $jo->setHasCoolant(false); + + // has motolite battery + $cv = $jo->getCustomerVehicle(); + $has_motolite = $req->request->get('has_motolite', 'false'); + if ($has_motolite == 'true') + $cv->setHasMotoliteBattery(true); + else + $cv->setHasMotoliteBattery(false); + $this->em->persist($cv); + + // check battery id + $batt_id = $req->request->get('batt_id', null); + // no battery + if ($batt_id == 0 || $batt_id == null) + $battery = null; + else + { + $battery = $this->em->getRepository(Battery::class)->find($batt_id); + if ($battery == null) + { + $data = [ + 'error' => 'Invalid battery id - ' . $batt_id + ]; + return $data; + } + } + + // check trade in + $trade_in = $req->request->get('trade_in'); + if (!TradeInType::validate($trade_in)) + $trade_in = null; + + // check mode of payment + $mode = $req->request->get('mode_of_payment'); + if (!ModeOfPayment::validate($mode)) + $mode = ModeOfPayment::CASH; + $jo->setModeOfPayment($mode); + + // generate new invoice + $crit = new InvoiceCriteria(); + $crit->setServiceType($stype_id); + $crit->setCustomerVehicle($cv); + $crit->setHasCoolant($jo->hasCoolant()); + + if ($promo != null) + $crit->addPromo($promo); + + if ($battery != null) + { + $crit->addEntry($battery, $trade_in, 1); + error_log('adding entry for battery - ' . $battery->getID()); + } + + $invoice = $this->ic->generateInvoice($crit); + + // remove previous invoice + $old_invoice = $jo->getInvoice(); + $this->em->remove($old_invoice); + $this->em->flush(); + + // save job order + $jo->setServiceType($stype_id); + + // save invoice + $jo->setInvoice($invoice); + $this->em->persist($invoice); + + // add event log + $rider = $this->session->getRider(); + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::RIDER_EDIT) + ->setJobOrder($jo) + ->setRider($rider); + $this->em->persist($event); + + $this->em->flush(); + // TODO: send mqtt event (?) + + return $data; + } + + protected function checkMissingParameters(Request $req, $params = []) + { + $missing = []; + + // check if parameters are there + foreach ($params as $param) + { + if ($req->getMethod() == 'GET') + { + $check = $req->query->get($param); + if ($check == null) + $missing[] = $param; + } + else if ($req->getMethod() == 'POST') + { + $check = $req->request->get($param); + if ($check == null) + $missing[] = $param; + } + else + return $params; + } + + return $missing; + } + + protected function checkParamsAndKey(Request $req, $params) + { + $data = []; + + // check for api_key in query string + $api_key = $req->query->get('api_key'); + if (empty($api_key)) + { + $data = [ + 'error' => 'Missing API key' + ]; + return $data; + } + + // check missing parameters + $missing = $this->checkMissingParameters($req, $params); + if (count($missing) > 0) + { + $miss_string = implode(', ', $missing); + $data = [ + 'error' => 'Missing parameter(s): ' . $miss_string + ]; + return $data; + } + + // check api key + $sess = $this->checkAPIKey($req->query->get('api_key')); + if ($sess == null) + { + $data = [ + 'error' => 'Invalid API Key' + ]; + return $data; + } + + // store session + $this->session = $sess; + + return $data; + } + + protected function checkAPIKey($api_key) + { + // find the api key (session id) + $session = $this->em->getRepository(RiderSession::class)->find($api_key); + if ($session == null) + return null; + + return $session; + } + + protected function checkJO(Request $req, $required_params, &$jo = null) + { + // set jo status to in transit + $data = $this->checkParamsAndKey($req, $required_params); + if (isset($data['error'])) + return $data; + + // are we logged in? + if (!$this->session->hasRider()) + { + $data = [ + 'error' => 'No logged in rider.' + ]; + return $data; + } + + $rider = $this->session->getRider(); + + // check if we have an active JO + $jo = $rider->getActiveJobOrder(); + if ($jo == null) + { + $data = [ + 'error' => 'No active job order.' + ]; + return $data; + } + + // check if the jo_id sent is the same as our active jo + if ($req->request->get('jo_id') != $jo->getID()) + { + $data = [ + 'error' => 'Job order selected is not active job order.' + ]; + return $data; + } + + return $data; + } + + protected function debugRequest(Request $req) + { + $all = $req->request->all(); + error_log(print_r($all, true)); + } +} diff --git a/src/Service/RiderAPIHandlerInterface.php b/src/Service/RiderAPIHandlerInterface.php new file mode 100644 index 00000000..753ee5cb --- /dev/null +++ b/src/Service/RiderAPIHandlerInterface.php @@ -0,0 +1,34 @@ +