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 (empty($check)) $missing[] = $param; } else if ($req->getMethod() == 'POST') { $check = $req->request->get($param); if (empty($check)) $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(MobileSession::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) { $res = new APIResult(); // confirm parameters $required_params = [ 'phone_model', 'os_type', 'os_version', 'phone_id' ]; $missing = $this->checkMissingParameters($req, $required_params); if (count($missing) > 0) { $params = implode(', ', $missing); $res->setError(true) ->setErrorMessage('Missing parameter(s): ' . $params); return $res->getReturnResponse(); } $em = $this->getDoctrine()->getManager(); // retry until we get a unique id while (true) { try { // instantiate session $sess = new MobileSession(); $sess->setPhoneModel($req->request->get('phone_model')) ->setOSType($req->request->get('os_type')) ->setOSVersion($req->request->get('os_version')) ->setPhoneID($req->request->get('phone_id')); // reopen in case we get an exception if (!$em->isOpen()) { $em = $em->create( $em->getConnection(), $em->getConfiguration() ); } // save $em->persist($sess); $em->flush(); } catch (DBALException $e) { error_log($e->getMessage()); // delay one second and try again sleep(1); continue; } break; } // return data $data = [ 'session_id' => $sess->getID() ]; $res->setData($data); // response return $res->getReturnResponse(); } protected function generateConfirmCode() { return sprintf("%06d", mt_rand(100000, 999999)); } public function confirmNumber(RisingTideGateway $rt, Request $req) { // check parameters $required_params = [ 'phone_number', ]; // check required parameters and api key $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // phone number $phone_number = $req->request->get('phone_number'); // TODO: spam protection // TODO: validate phone number // generate code and save // $code = '123456'; $code = $this->generateConfirmCode(); $this->session->setConfirmCode($code) ->setPhoneNumber($phone_number); $em->flush(); // send sms to number $message = "Your Resq confirmation code is $code."; $rt->sendSMS($phone_number, 'MOTOLITE', $message); // response return $res->getReturnResponse(); } // TODO: find session customer by phone number protected function findNumberSession($number) { $em = $this->getDoctrine()->getManager(); $query = $em->getRepository(MobileSession::class)->createQueryBuilder('s') ->where('s.phone_number = :number') ->andWhere('s.customer is not null') ->andWhere('s.confirm_flag = 1') ->setParameter('number', $number) ->setMaxResults(1) ->getQuery(); // we just need one $res = $query->getOneOrNullResult(); return $res; } public function validateCode(Request $req) { // check parameters $required_params = [ 'code', ]; // check required parameters and api key $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // code is wrong $code = $req->request->get('code'); if ($this->session->getConfirmCode() != $code) { $res->setError(true) ->setErrorMessage('Wrong confirm code'); return $res->getReturnResponse(); } // set confirm date $date = new DateTime(); $this->session->setDateConfirmed($date) ->setConfirmed(); // TODO: check if we have the number registered before and merge $dupe_sess = $this->findNumberSession($this->session->getPhoneNumber()); if ($dupe_sess != null) { $dupe_cust = $dupe_sess->getCustomer(); $this->session->setCustomer($dupe_cust); } $em->flush(); // response return $res->getReturnResponse(); } public function getInfo(Request $req) { // check required parameters and api key $required_params = []; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // if no customer found $cust = $this->session->getCustomer(); if ($cust == null) { $data = [ 'first_name' => '', 'last_name' => '', ]; $res->setData($data); return $res->getReturnResponse(); } // send back customer details $data = [ 'first_name' => $cust->getFirstName(), 'last_name' => $cust->getLastName(), ]; $res->setData($data); return $res->getReturnResponse(); } public function updateInfo(Request $req) { // check required parameters and api key $required_params = [ 'first_name', 'last_name', ]; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // create new customer if it's not there $cust = $this->session->getCustomer(); if ($cust == null) { $cust = new Customer(); $em->persist($cust); $this->session->setCustomer($cust); } $cust->setFirstName($req->request->get('first_name')) ->setLastName($req->request->get('last_name')) ->setConfirmed($this->session->isConfirmed()); // update mobile phone of customer $cust->setPhoneMobile(substr($this->session->getPhoneNumber(), 2)); $em->flush(); return $res->getReturnResponse(); } public function getStatus(Request $req) { // check required parameters and api key $required_params = []; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // set data $data = []; if ($this->session->isConfirmed()) $data['status'] = 'confirmed'; else $data['status'] = 'unconfirmed'; $res->setData($data); return $res->getReturnResponse(); } public function listVehicleManufacturers(Request $req) { // check required parameters and api key $required_params = []; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // get manufacturer list $mfgs = $em->getRepository(VehicleManufacturer::class)->findBy(['flag_mobile' => true], ['name' => 'asc']); $mfg_list = []; foreach ($mfgs as $mfg) { $mfg_list[] = [ 'id' => $mfg->getID(), 'name' => $mfg->getName(), ]; } $data = [ 'manufacturers' => $mfg_list ]; $res->setData($data); return $res->getReturnResponse(); } public function listVehicleMakes(Request $req, $mfg_id) { // check required parameters and api key $required_params = []; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // get manufacturer $mfg = $em->getRepository(VehicleManufacturer::class)->find($mfg_id); if ($mfg == null) { $res->setError(true) ->setErrorMessage('Invalid vehicle manufacturer id'); return $res->getReturnResponse(); } // get makes $vehicles = $em->getRepository(Vehicle::class)->findBy( [ 'flag_mobile' => true, 'manufacturer' => $mfg_id, ], ['make' => 'asc'] ); // $vehicles = $mfg->getVehicles(); $vlist = []; foreach ($vehicles as $v) { $vlist[] = [ 'id' => $v->getID(), 'make' => trim($v->getMake() . ' ' . $v->getModelYearFormatted(false)), // 'make' => $v->getMake() . ' ' . $v->getModelYearFrom() . '-' . $v->getModelYearTo(), ]; } $data = [ 'manufacturer' => [ 'id' => $mfg->getID(), 'name' => $mfg->getName(), ], 'makes' => $vlist, ]; $res->setData($data); return $res->getReturnResponse(); } protected function checkVehicleRequirements(Request $req) { // check required parameters and api key $required_params = [ 'make_id', 'name', 'plate_num', 'model_year', 'color', 'condition', 'fuel_type', ]; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res; // TODO: check valid plate number // TODO: check valid fuel type (gas / diesel) // TODO: check current battery id // TODO: check condition (brand new / second-hand) // TODO: check is_motolite and is_active (1 or 0) // TODO: check warranty expiration date (YYYYMMDD) // TODO: check model year coverage if it fits in between return $res; } protected function setCustomerVehicleObject(Request $req, APIResult $res, CustomerVehicle $cv) { $em = $this->getDoctrine()->getManager(); // check customer $cust = $this->session->getCustomer(); if ($cust == null) { $res->setError(true) ->setErrorMessage('No customer information found'); return $res; } // get vehicle $vehicle = $em->getRepository(Vehicle::class)->find($req->request->get('make_id')); if ($vehicle == null) { $res->setError(true) ->setErrorMessage('Invalid vehicle make id'); return $res; } $cv->setCustomer($cust) ->setVehicle($vehicle) ->setName($req->request->get('name')) ->setPlateNumber($req->request->get('plate_num')) ->setModelYear($req->request->get('model_year')) ->setColor($req->request->get('color')) ->setFuelType($req->request->get('fuel_type')) ->setStatusCondition($req->request->get('condition')); // set warranty code and expiration // TODO: check warranty requirements if (!empty($req->request->get('wty_code'))) $cv->setWarrantyCode($req->request->get('wty_code')); if (!empty($req->request->get('wty_expire'))) $cv->setWarrantyExpiration(new DateTime($req->request->get('wty_expire'))); // TODO: get current battery // is motolite if ($req->request->get('is_motolite') == 0) $cv->setHasMotoliteBattery(false); else $cv->setHasMotoliteBattery(true); // is active if ($req->request->get('is_active') == 0) $cv->setActive(false); else $cv->setActive(true); // save $em->persist($cv); $em->flush(); // data $data = [ 'cv_id' => $cv->getID() ]; $res->setData($data); return $res; } public function addVehicle(Request $req) { // check requirements $res = $this->checkVehicleRequirements($req); if ($res->isError()) return $res->getReturnResponse(); // customer vehicle $cv = new CustomerVehicle(); $res = $this->setCustomerVehicleObject($req, $res, $cv); return $res->getReturnResponse(); } public function updateVehicle(Request $req, $id) { // check requirements $res = $this->checkVehicleRequirements($req); if ($res->isError()) return $res->getReturnResponse(); // get customer vehicle $em = $this->getDoctrine()->getManager(); $cv = $em->getRepository(CustomerVehicle::class)->find($id); // check if it exists if ($cv == null) { $res->setError(true) ->setErrorMessage('Vehicle does not exist'); return $res->getReturnResponse(); } // check if it's owned by customer if ($cv->getCustomer()->getID() != $this->session->getCustomer()->getID()) { $res->setError(true) ->setErrorMessage('Invalid vehicle'); return $res->getReturnResponse(); } $res = $this->setCustomerVehicleObject($req, $res, $cv); return $res->getReturnResponse(); } 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; } public function listVehicles(Request $req) { // check required parameters and api key $required_params = []; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // customer $cust = $this->session->getCustomer(); if ($cust == null) { $res->setError(true) ->setErrorMessage('No customer information found'); return $res->getReturnResponse(); } // vehicles $cv_list = []; $cvs = $cust->getVehicles(); foreach ($cvs as $cv) { $battery_id = null; if ($cv->getCurrentBattery() != null) $battery_id = $cv->getCurrentBattery()->getID(); $wty_ex = null; if ($cv->getWarrantyExpiration() != null) $wty_ex = $cv->getWarrantyExpiration()->format('Y-m-d'); $cv_list[] = [ 'cv_id' => $cv->getID(), 'mfg_id' => $cv->getVehicle()->getManufacturer()->getID(), 'make_id' => $cv->getVehicle()->getID(), 'name' => $cv->getName(), 'plate_num' => $cv->getPlateNumber(), 'model_year' => $cv->getModelYear(), 'color' => $cv->getColor(), 'condition' => $cv->getStatusCondition(), 'fuel_type' => $cv->getFuelType(), 'wty_code' => $cv->getWarrantyCode(), 'wty_expire' => $wty_ex, 'curr_batt_id' => $battery_id, 'is_motolite' => $cv->hasMotoliteBattery() ? 1 : 0, 'is_active' => $cv->isActive() ? 1 : 0, ]; } // data $data = [ 'vehicles' => $cv_list ]; $res->setData($data); return $res->getReturnResponse(); } public function listPromos(Request $req) { // check required parameters and api key $required_params = []; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); return $res->getReturnResponse(); } public function getCompatibleBatteries(Request $req, $vid) { // check required parameters and api key $required_params = []; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // get vehicle $vehicle = $em->getRepository(Vehicle::class)->find($vid); if ($vehicle == null) { $res->setError(true) ->setErrorMessage('Invalid vehicle'); return $res->getReturnResponse(); } // batteries $batt_list = []; $batts = $vehicle->getBatteries(); foreach ($batts as $batt) { $batt_list[] = [ 'id' => $batt->getID(), 'mfg_id' => $batt->getManufacturer()->getID(), 'mfg_name' => $batt->getManufacturer()->getName(), 'model_id' => $batt->getModel()->getID(), 'model_name' => $batt->getModel()->getName(), 'size_id' => $batt->getSize()->getID(), 'size_name' => $batt->getSize()->getName(), 'price' => $batt->getSellingPrice(), 'wty_private' => $batt->getWarrantyPrivate(), 'wty_commercial' => $batt->getWarrantyCommercial(), 'image_url' => $this->getBatteryImageURL($req, $batt), ]; } // data $data = [ 'vehicle' => [ 'id' => $vehicle->getID(), 'mfg_id' => $vehicle->getManufacturer()->getID(), 'mfg_name' => $vehicle->getManufacturer()->getName(), 'make' => $vehicle->getMake(), 'model_year_from' => $vehicle->getModelYearFrom(), 'model_year_to' => $vehicle->getModelYearTo(), ], 'batteries' => $batt_list, ]; $res->setData($data); return $res->getReturnResponse(); } public function requestJobOrder(Request $req, InvoiceCreator $ic) { // check required parameters and api key $required_params = [ 'service_type', 'cv_id', // 'batt_id', 'trade_in', 'long', 'lat', 'warranty', 'mode_of_payment', ]; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // trade in type $trade_in = $req->request->get('trade_in'); // address $address = $req->request->get('delivery_address', 'Set by mobile application'); // instructions $instructions = $req->request->get('delivery_instructions', ''); $jo = new JobOrder(); $jo->setSource(TransactionOrigin::MOBILE_APP) ->setStatus(JOStatus::PENDING) ->setDeliveryInstructions('') ->setTier1Notes('') ->setTier2Notes('') ->setDeliveryAddress($address) ->setTradeInType($trade_in) ->setDeliveryInstructions($instructions) // TODO: error check for valid mode of payment ->setModeOfPayment($req->request->get('mode_of_payment')); // customer $cust = $this->session->getCustomer(); if ($cust == null) { $res->setError(true) ->setErrorMessage('No customer information found'); return $res->getReturnResponse(); } $jo->setCustomer($cust); // validate service type $stype = $req->request->get('service_type'); if (!ServiceType::validate($stype)) { $res->setError(true) ->setErrorMessage('Invalid service type'); return $res->getReturnResponse(); } $jo->setServiceType($stype); // validate warranty $warr = $req->request->get('warranty'); if (!WarrantyClass::validate($warr)) { $res->setError(true) ->setErrorMessage('Invalid warranty class'); return $res->getReturnResponse(); } $jo->setWarrantyClass($warr); // longitude and latitude $long = $req->request->get('long'); $lat = $req->request->get('lat'); $point = new Point($long, $lat); $jo->setCoordinates($point); // make invoice criteria $icrit = new InvoiceCriteria(); $icrit->setServiceType($stype); // check promo $promo_id = $req->request->get('promo_id'); if (!empty($promo_id)) { $promo = $em->getRepository(Promo::class)->find($promo_id); if ($promo == null) { $res->setError(true) ->setErrorMessage('Invalid promo id'); return $res->getReturnResponse(); } // put in criteria $icrit->addPromo($promo); } // check customer vehicle $cv = $em->getRepository(CustomerVehicle::class)->find($req->request->get('cv_id')); if ($cv == null) { $res->setError(true) ->setErrorMessage('Invalid customer vehicle id'); return $res->getReturnResponse(); } $icrit->setCustomerVehicle($cv); $jo->setCustomerVehicle($cv); // check if customer owns vehicle if ($cust->getID() != $cv->getCustomer()->getID()) { $res->setError(true) ->setErrorMessage('Customer does not own vehicle'); return $res->getReturnResponse(); } // check battery $batt_id = $req->request->get('batt_id'); if ($batt_id != null) { $batt = $em->getRepository(Battery::class)->find($batt_id); if ($batt == null) { $res->setError(true) ->setErrorMessage('Invalid battery id'); return $res->getReturnResponse(); } } else $batt = null; /* // put battery in criteria $icrit->addBattery($batt); */ // check trade-in // only allow motolite, other, none switch ($trade_in) { case TradeInType::MOTOLITE: case TradeInType::OTHER: break; default: $trade_in = ''; break; } $icrit->addEntry($batt, $trade_in, 1); // send to invoice generator $invoice = $ic->processCriteria($icrit); $jo->setInvoice($invoice); $em->persist($jo); $em->persist($invoice); // add event log $event = new JOEvent(); $event->setDateHappen(new DateTime()) ->setTypeID(JOEventType::CREATE) ->setJobOrder($jo); $em->persist($event); $em->flush(); // make invoice json data $invoice_data = [ 'total_price' => $invoice->getTotalPrice(), 'vat_ex_price' => $invoice->getVATExclusivePrice(), 'vat' => $invoice->getVAT(), 'discount' => $invoice->getDiscount(), 'trade_in' => $invoice->getTradeIn(), ]; $items = $invoice->getItems(); $items_data = []; foreach ($items as $item) { $items_data[] = [ 'title' => $item->getTitle(), 'qty' => $item->getQuantity() + 0, 'price' => $item->getPrice() + 0.0, ]; } $invoice_data['items'] = $items_data; // make job order data $data = [ 'jo_id' => $jo->getID(), 'invoice' => $invoice_data ]; // set data $res->setData($data); return $res->getReturnResponse(); } public function getEstimate(Request $req, InvoiceCreator $ic) { // check required parameters and api key $required_params = [ 'service_type', 'cv_id', // 'batt_id', 'trade_in', ]; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // customer $cust = $this->session->getCustomer(); if ($cust == null) { $res->setError(true) ->setErrorMessage('No customer information found'); return $res->getReturnResponse(); } // make invoice criteria $icrit = new InvoiceCriteria(); $icrit->setServiceType($req->request->get('service_type')); // check promo $promo_id = $req->request->get('promo_id'); if (!empty($promo_id)) { $promo = $em->getRepository(Promo::class)->find($promo_id); if ($promo == null) { $res->setError(true) ->setErrorMessage('Invalid promo id'); return $res->getReturnResponse(); } // put in criteria $icrit->addPromo($promo); } // check customer vehicle $cv = $em->getRepository(CustomerVehicle::class)->find($req->request->get('cv_id')); if ($cv == null) { $res->setError(true) ->setErrorMessage('Invalid customer vehicle id'); return $res->getReturnResponse(); } $icrit->setCustomerVehicle($cv); // check if customer owns vehicle if ($cust->getID() != $cv->getCustomer()->getID()) { $res->setError(true) ->setErrorMessage('Customer does not own vehicle'); return $res->getReturnResponse(); } // check battery $batt_id = $req->request->get('batt_id'); if ($batt_id != null) { $batt = $em->getRepository(Battery::class)->find($batt_id); if ($batt == null) { $res->setError(true) ->setErrorMessage('Invalid battery id'); return $res->getReturnResponse(); } } else $batt = null; /* // put battery in criteria $icrit->addBattery($batt); */ // check trade-in // only allow motolite, other, none $trade_in = $req->request->get('trade_in'); switch ($trade_in) { case TradeInType::MOTOLITE: case TradeInType::OTHER: break; default: $trade_in = ''; break; } $icrit->addEntry($batt, $trade_in, 1); // send to invoice generator $invoice = $ic->processCriteria($icrit); // make invoice json data $data = [ 'total_price' => $invoice->getTotalPrice(), 'vat_ex_price' => $invoice->getVATExclusivePrice(), 'vat' => $invoice->getVAT(), 'discount' => $invoice->getDiscount(), 'trade_in' => $invoice->getTradeIn(), ]; $items = $invoice->getItems(); $items_data = []; foreach ($items as $item) { $my_data = [ 'title' => $item->getTitle(), 'qty' => $item->getQuantity() + 0, 'price' => $item->getPrice() + 0.0, ]; $item_batt = $item->getBattery(); if ($item_batt != null) { $my_data['image_url'] = $this->getBatteryImageURL($req, $batt); } $items_data[] = $my_data; } $data['items'] = $items_data; error_log(print_r($data, true)); // set data $res->setData($data); return $res->getReturnResponse(); } public function getRiderStatus(Request $req) { $required_params = []; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // get customer $cust = $this->session->getCustomer(); if ($cust == null) { $res->setError(true) ->setErrorMessage('No customer information found'); return $res->getReturnResponse(); } // check if we have an ongoing job order $ongoing_jos = $em->getRepository(JobOrder::class)->findBy([ 'customer' => $cust, 'status' => [JOStatus::PENDING, JOStatus::RIDER_ASSIGN, JOStatus::IN_TRANSIT, JOStatus::ASSIGNED, JOStatus::IN_PROGRESS], ]); if (count($ongoing_jos) <= 0) { $res->setData([ 'status' => APIRiderStatus::NO_PENDING_JO ]); return $res->getReturnResponse(); } // get first jo that's pending $jo = $ongoing_jos[0]; $dest = $jo->getCoordinates(); $data = [ 'jo_id' => $jo->getID(), 'service_type' => $jo->getServiceType(), 'destination' => [ 'long' => $dest->getLongitude(), 'lat' => $dest->getLatitude(), ], 'delivery_address' => $jo->getDeliveryAddress(), 'delivery_instructions' => $jo->getDeliveryInstructions(), ]; switch ($jo->getStatus()) { case JOStatus::PENDING: $data['status'] = APIRiderStatus::OUTLET_ASSIGN; $res->setData($data); return $res->getReturnResponse(); case JOStatus::RIDER_ASSIGN: $data['status'] = APIRiderStatus::RIDER_ASSIGN; $res->setData($data); return $res->getReturnResponse(); case JOStatus::ASSIGNED: case JOStatus::IN_TRANSIT: case JOStatus::IN_PROGRESS: $coord = $jo->getHub()->getCoordinates(); $rider = $jo->getRider(); // 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(); $data['status'] = APIRiderStatus::RIDER_PICK_UP; // TODO: fix this to actual location of rider $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() ] ]; return $res->getReturnResponse(); } $res->setData($data); return $res->getReturnResponse(); } public function getOngoing(Request $req) { $required_params = []; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // get customer $cust = $this->session->getCustomer(); if ($cust == null) { $res->setError(true) ->setErrorMessage('No customer information found'); return $res->getReturnResponse(); } // check if we have an ongoing job order $ongoing_jos = $em->getRepository(JobOrder::class)->findBy([ 'customer' => $cust, 'status' => [JOStatus::PENDING, JOStatus::RIDER_ASSIGN, JOStatus::ASSIGNED, JOStatus::IN_PROGRESS], ]); // initialize data $data = []; // no ongoing if (count($ongoing_jos) <= 0) { $data = [ 'has_ongoing' => false, ]; } else { $data = [ 'has_ongoing' => true, ]; } $res->setData($data); return $res->getReturnResponse(); } public function addRiderRating(Request $req) { $required_params = [ 'jo_id', 'rating', ]; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // get customer $cust = $this->session->getCustomer(); if ($cust == null) { $res->setError(true) ->setErrorMessage('No customer information found'); return $res->getReturnResponse(); } // get job order $jo_id = $req->request->get('jo_id'); $jo = $em->getRepository(JobOrder::class)->find($jo_id); if ($jo == null) { $res->setError(true) ->setErrorMessage('No job order found'); return $res->getReturnResponse(); } // get rider $rider = $jo->getRider(); if ($rider == null) { $res->setError(true) ->setErrorMessage('No rider found'); return $res->getReturnResponse(); } // check that the customer owns the job order $jo_cust = $jo->getCustomer(); if ($jo_cust->getID() != $cust->getID()) { $res->setError(true) ->setErrorMessage('Job order was not initiated by customer'); return $res->getReturnResponse(); } // TODO: check job order status, if it's complete // add rider rating $rating_num = $req->request->get('rating'); $rating = new RiderRating(); $rating->setRider($rider) ->setCustomer($cust) ->setJobOrder($jo) ->setRating($rating_num); // rider rating comment $comment = $req->request->get('comment'); if (!empty($comment)) $rating->setComment($comment); $em->persist($rating); $em->flush(); // TODO: set average rating in rider entity $res->setData([]); return $res->getReturnResponse(); } public function cancelJobOrder(Request $req, MQTTClient $mclient) { $required_params = [ 'jo_id', 'reason' ]; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // get job order $jo_id = $req->request->get('jo_id'); $jo = $em->getRepository(JobOrder::class)->find($jo_id); if ($jo == null) { $res->setError(true) ->setErrorMessage('No job order found'); return $res->getReturnResponse(); } // get customer $cust = $this->session->getCustomer(); if ($cust == null) { $res->setError(true) ->setErrorMessage('No customer information found'); return $res->getReturnResponse(); } // check that the customer owns the job order $jo_cust = $jo->getCustomer(); if ($jo_cust->getID() != $cust->getID()) { $res->setError(true) ->setErrorMessage('Job order was not initiated by customer'); return $res->getReturnResponse(); } // 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(); // send mobile app event $payload = [ 'event' => 'cancelled', 'reason' => $cancel_reason, 'jo_id' => $jo->getID(), ]; $mclient->sendEvent($jo, $payload); $mclient->sendRiderEvent($jo, $payload); $res->setData([]); return $res->getReturnResponse(); } public function getJOHistory(Request $req) { $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, []); if ($res->isError()) return $res->getReturnResponse(); // get customer $cust = $this->session->getCustomer(); if ($cust == null) { $res->setError(true) ->setErrorMessage('No customer information found'); return $res->getReturnResponse(); } // get job orders $all_jo_data = []; $jos = $cust->getJobOrders(); foreach ($jos as $jo) { $status = $jo->getStatus(); $jo_data = [ 'id' => $jo->getID(), 'date_create' => $jo->getDateCreate()->format('M d, Y'), 'service_type' => $jo->getServiceType(), 'status' => $status, ]; // customer vehicle $cv = $jo->getCustomerVehicle(); $jo_data['customer_vehicle'] = [ 'id' => $cv->getID(), 'plate_number' => $cv->getPlateNumber(), ]; // rider $rider = $jo->getRider(); if ($rider != null) { $jo_data['rider'] = $rider->getFullName(); } // 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; } $all_jo_data[] = $jo_data; } // return data $data = [ 'job_orders' => $all_jo_data ]; $res->setData($data); // response return $res->getReturnResponse(); } public function updateDeviceID(Request $req) { $required_params = [ 'device_id', ]; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); $device_id = $req->request->get('device_id'); $this->session->setDevicePushID($device_id); $em->flush(); // response return $res->getReturnResponse(); } public function resendCode(Request $req) { $required_params = []; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // already confirmed if ($this->session->isConfirmed()) { $res->setError(true) ->setErrorMessage('User is already confirmed.'); return $res->getReturnResponse(); } // have sent code before if ($this->session->getDateCodeSent() != null) { $res->setError(true) ->setErrorMessage('Can only send confirm code every 5 mins.'); return $res->getReturnResponse(); } // TODO: send via sms return $res->getReturnResponse(); } public function privacySettings(Request $req) { $required_params = [ 'priv_third_party', // 'priv_promo', ]; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); // get customer $cust = $this->session->getCustomer(); if ($cust == null) { $res->setError(true) ->setErrorMessage('No customer information found'); return $res->getReturnResponse(); } // set privacy settings $priv_promo = $req->request->get('priv_promo', false); $cust->setPrivacyThirdParty($req->request->get('priv_third_party')) ->setPrivacyPromo($priv_promo); $em->flush(); return $res->getReturnResponse(); } public function locationSupport(Request $req) { $required_params = [ 'longitude', 'latitude', ]; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); $data = [ 'longitude' => $req->query->get('longitude'), 'latitude' => $req->query->get('latitude'), 'supported' => true, ]; $res->setData($data); return $res->getReturnResponse(); } }