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', 'device_push_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')) ->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(); } 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(); } public function confirmNumber(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 // TODO: generate code and save // use '123456' for now $code = '123456'; $this->session->setConfirmCode($code) ->setPhoneNumber($phone_number); $em->flush(); // TODO: send sms to number // response return $res->getReturnResponse(); } 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(); $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()); $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([], ['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 = $mfg->getVehicles(); $vlist = []; foreach ($vehicles as $v) { $vlist[] = [ 'id' => $v->getID(), '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(); } 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(), ]; } // 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', ]; $em = $this->getDoctrine()->getManager(); $res = $this->checkParamsAndKey($req, $em, $required_params); if ($res->isError()) return $res->getReturnResponse(); $jo = new JobOrder(); $jo->setSource(TransactionOrigin::MOBILE_APP) ->setStatus(JOStatus::PENDING) ->setDeliveryInstructions('') ->setTier1Notes('') ->setTier2Notes('') ->setDeliveryAddress('Set by mobile application'); // 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(); } $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 = $em->getRepository(Battery::class)->find($req->request->get('batt_id')); if ($batt == null) { $res->setError(true) ->setErrorMessage('Invalid battery id'); return $res->getReturnResponse(); } // put battery in criteria $icrit->addBattery($batt); // TODO: check trade-in // send to invoice generator $invoice = $ic->processCriteria($icrit); $jo->setInvoice($invoice); $em->persist($jo); $em->persist($invoice); $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 = [ '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(); // 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(); } // 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 = $em->getRepository(Battery::class)->find($req->request->get('batt_id')); if ($batt == null) { $res->setError(true) ->setErrorMessage('Invalid battery id'); return $res->getReturnResponse(); } // put battery in criteria $icrit->addBattery($batt); // TODO: check trade-in // 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) { $items_data[] = [ 'title' => $item->getTitle(), 'qty' => $item->getQuantity() + 0, 'price' => $item->getPrice() + 0.0, ]; } $data['items'] = $items_data; // 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::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(); switch ($jo->getStatus()) { case JOStatus::PENDING: $res->setData([ 'status' => APIRiderStatus::OUTLET_ASSIGN, 'jo_id' => $jo->getID(), 'destination' => [ 'long' => $dest->getLongitude(), 'lat' => $dest->getLatitude(), ], ]); return $res->getReturnResponse(); case JOStatus::RIDER_ASSIGN: $res->setData([ 'status' => APIRiderStatus::RIDER_ASSIGN, 'jo_id' => $jo->getID(), 'destination' => [ 'long' => $dest->getLongitude(), 'lat' => $dest->getLatitude(), ], ]); return $res->getReturnResponse(); case JOStatus::ASSIGNED: $coord = $jo->getHub()->getCoordinates(); $rider = $jo->getRider(); // TODO: figure out cleaner way to generate urls $image_url = 'http://resq.jankstudio.com/assets/images/user.gif'; if ($rider->getImageFile() != null) $image_url = 'http://resq.jankstudio.com/uploads/' . $rider->getImageFile(); $res->setData([ 'status' => APIRiderStatus::RIDER_PICK_UP, 'jo_id' => $jo->getID(), 'destination' => [ 'long' => $dest->getLongitude(), 'lat' => $dest->getLatitude(), ], // TODO: fix this to actual location of rider '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); $em->persist($rating); $em->flush(); // TODO: set average rating in rider entity $res->setData([]); return $res->getReturnResponse(); } public function cancelJobOrder(Request $req) { $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 $jo->setStatus(JOStatus::CANCELLED) ->setDateCancel(new DateTime()) ->setCancelReason($req->request->get('reason')); $em->flush(); $res->setData([]); return $res->getReturnResponse(); } }