diff --git a/config/routes/api.yaml b/config/routes/api.yaml index b880d436..3c4a5b39 100644 --- a/config/routes/api.yaml +++ b/config/routes/api.yaml @@ -185,3 +185,38 @@ api_jo_info: path: /api/job_order/{id}/info controller: App\Controller\APIController::getJobOrderInfo methods: [GET] + +api_ongoing_job_orders: + path: /api/job_orders/ongoing + controller: App\Controller\APIController::getAllOngoingJobOrders + methods: [GET] + +api_ongoing_jo_count: + path: /api/job_orders/ongoing/count + controller: App\Controller\APIController::getOngoingJobOrderCount + methods: [GET] + +api_new_location: + path: /api/new_location + controller: App\Controller\APIController::addLocation + methods: [POST] + +api_locations: + path: /api/locations + controller: App\Controller\APIController::getLocations + methods: [GET] + +api_cust_vehicle_remove: + path: /api/vehicles/{id}/remove + controller: App\Controller\APIController::removeVehicle + methods: [POST] + +api_latest_job_order: + path: /api/job_order/latest + controller: App\Controller\APIController::getLatestJobOrder + methods: [GET] + +#api_completed_job_orders: +# path: /api/job_orders/completed +# controller: App\Controller\APIController::getCompletedJobOrders +# methods: [GET] diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index b29df821..0502bc17 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -66,6 +66,7 @@ use App\Entity\PrivacyPolicy; use App\Entity\Hub; use App\Entity\SAPBattery; use App\Entity\WarrantySerial; +use App\Entity\CustomerMetadata; use DateTime; use DateInterval; @@ -741,7 +742,9 @@ class APIController extends Controller implements LoggedController // vehicles $cv_list = []; - $cvs = $cust->getVehicles(); + // $cvs = $cust->getVehicles(); + // only get the customer's vehicles whose flag_active is true + $cvs = $em->getRepository(CustomerVehicle::class)->findBy(['flag_active' => true, 'customer' => $cust]); foreach ($cvs as $cv) { $battery_id = null; @@ -1542,7 +1545,7 @@ class APIController extends Controller implements LoggedController $ongoing_jos = $em->getRepository(JobOrder::class)->findBy([ 'customer' => $cust, 'status' => [JOStatus::PENDING, JOStatus::RIDER_ASSIGN, JOStatus::IN_TRANSIT, JOStatus::ASSIGNED, JOStatus::IN_PROGRESS], - ]); + ], ['date_schedule' => 'desc']); return $ongoing_jos; } @@ -1912,18 +1915,18 @@ class APIController extends Controller implements LoggedController { $status = $jo->getStatus(); - $dest = $jo->getCoordinates(); + $dest = $jo->getCoordinates(); - $jo_data = [ - 'id' => $jo->getID(), + $jo_data = [ + 'id' => $jo->getID(), 'date_create' => $jo->getDateCreate()->format('M d, Y'), - 'service_type' => $jo->getServiceType(), - 'destination' => [ - 'long' => $dest->getLongitude(), - 'lat' => $dest->getLatitude(), - ], - 'delivery_address' => $jo->getDeliveryAddress(), - 'delivery_instructions' => $jo->getDeliveryInstructions(), + 'service_type' => $jo->getServiceType(), + 'destination' => [ + 'long' => $dest->getLongitude(), + 'lat' => $dest->getLatitude(), + ], + 'delivery_address' => $jo->getDeliveryAddress(), + 'delivery_instructions' => $jo->getDeliveryInstructions(), 'jo_status' => $status, 'status' => $this->generateAPIRiderStatus($status), ]; @@ -1940,6 +1943,14 @@ class APIController extends Controller implements LoggedController 'warranty' => $warranty, ]; + // customer information + $customer = $jo->getCustomer(); + $jo_data['customer'] = [ + 'first_name' => $customer->getFirstName(), + 'last_name' => $customer->getLastName(), + 'mobile_number' => $customer->getPhoneMobile(), + ]; + // rider $rider = $jo->getRider(); if ($rider != null) @@ -2023,7 +2034,12 @@ class APIController extends Controller implements LoggedController // get job orders $all_jo_data = []; - $jos = $cust->getJobOrders(); + // $jos = $cust->getJobOrders(); + // get the fulfilled and cancelled job orders, since ongoing jos are not yet part of history + $jos = $em->getRepository(JobOrder::class)->findBy([ + 'customer' => $cust, + 'status' => [JOStatus::CANCELLED, JOStatus::FULFILLED] + ], ['date_schedule' => 'DESC']); foreach ($jos as $jo) { // NOTE: use generateJobOrderData method, maybe? @@ -2050,11 +2066,34 @@ class APIController extends Controller implements LoggedController // rider $rider = $jo->getRider(); + + // check if jo has rider rating set to true + $has_rider_rating = $jo->hasRiderRating(); + $rating = 0; + $comment = ''; if ($rider != null) { $jo_data['rider'] = $rider->getFullName(); + + // find the rider rating if any + if ($has_rider_rating) + { + $jo_rating = $jo->getRating(); + if ($jo_rating != null) + { + $rating = $jo_rating->getRating(); + + // get comment + $comment = $jo_rating->getComment(); + } + } } + // rider rating for jo + $jo_data['has_rider_rating'] = $has_rider_rating; + $jo_data['rider_rating'] = $rating; + $jo_data['comment'] = $comment; + // invoice items $items = []; $jo_items = $jo->getInvoice()->getItems(); @@ -2070,7 +2109,6 @@ class APIController extends Controller implements LoggedController $jo_data['items'] = $items; - // dates depending on status switch ($status) { @@ -2265,6 +2303,13 @@ class APIController extends Controller implements LoggedController ]; $res->setData($data); + // check if is_covered is false. If so, we need to set the error part in the response + if (!$is_covered) + { + $res->setError(true) + ->setErrorMessage('Oops! Our service is limited to some areas in Metro Manila, Laguna, and Baguio only. We will update you as soon as we are able to cover your area'); + } + return $res->getReturnResponse(); } @@ -2507,6 +2552,23 @@ class APIController extends Controller implements LoggedController $partners = []; foreach($result as $row) { + // get all the reviews for each partner and average the ratings + $partner_id = $row[0]->getID(); + $partner = $em->getRepository(Partner::class)->find($partner_id); + $partner_reviews = $em->getRepository(Review::class)->findBy(['partner' => $partner]); + + $average_rating = 0; + if (count($partner_reviews) > 0) + { + $rating = 0; + foreach ($partner_reviews as $review) + { + $rating = $rating + $review->getRating(); + } + + $average_rating = $rating / sizeof($partner_reviews); + } + $partners[] = [ 'id' => $row[0]->getID(), 'name' => $row[0]->getName(), @@ -2518,6 +2580,7 @@ class APIController extends Controller implements LoggedController 'longitude' => $row[0]->getCoordinates()->getLongitude(), 'latitude' => $row[0]->getCoordinates()->getLatitude(), 'db_distance' => $row['dist'], + 'rating' => $average_rating, ]; } @@ -2670,6 +2733,9 @@ class APIController extends Controller implements LoggedController // instructions $instructions = $req->request->get('delivery_instructions', ''); + // landmark + $landmark = $req->request->get('landmark', ' '); + // longitude and latitude $long = $req->request->get('long'); $lat = $req->request->get('lat'); @@ -2708,6 +2774,14 @@ class APIController extends Controller implements LoggedController $hub = null; $hub_id = $req->request->get('hub_id'); + // check if hub_id is -1 which means user clicked Book Now before 5 PM + // but confirmed the order after 5 PM + if ($hub_id == -1) + { + $res->setError(true) + ->setErrorMessage('Book Now no longer available.'); + return $res->getReturnResponse(); + } if (strlen($hub_id) > 0) $hub = $em->getRepository(Hub::class)->find($hub_id); @@ -2747,7 +2821,8 @@ class APIController extends Controller implements LoggedController // TODO: error check for valid mode of payment ->setModeOfPayment($req->request->get('mode_of_payment')) ->setAdvanceOrder($flag_advance_order) - ->setStatusAutoAssign(AutoAssignStatus::NOT_ASSIGNED); + ->setStatusAutoAssign(AutoAssignStatus::NOT_ASSIGNED) + ->setLandmark($landmark); // customer // $cust = $this->session->getCustomer(); @@ -3157,6 +3232,9 @@ class APIController extends Controller implements LoggedController $api_version = $this->getParameter('api_version'); $app_version = $req->query->get('version'); + // putting this in for the future, in case we have diverging versions + $os = $req->query->get('os'); + $platform = $req->query->get('platform'); $api_v = explode('.', $api_version); $app_v = explode('.', $app_version); @@ -3526,6 +3604,290 @@ class APIController extends Controller implements LoggedController return $res->getReturnResponse(); } + public function getAllOngoingJobOrders(EntityManagerInterface $em, Request $req, RiderTracker $rt) + { + $required_params = []; + $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(); + } + + $ongoing_jos = $this->getOngoingJobOrders($cust); + + // initialize data + $jo_data = []; + foreach ($ongoing_jos as $jo) + { + $jo_data[] = $this->generateJobOrderData($req, $jo, $rt); + } + + $data = [ + 'ongoing_job_orders' => $jo_data, + ]; + + $res->setData($data); + + return $res->getReturnResponse(); + } + + public function getOngoingJobOrderCount(EntityManagerInterface $em, Request $req) + { + $required_params = []; + $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(); + } + + $ongoing_jos = $this->getOngoingJobOrders($cust); + + $data = [ + 'ongoing_job_order_count' => count($ongoing_jos), + ]; + + $res->setData($data); + + return $res->getReturnResponse(); + } + + public function addLocation(EntityManagerInterface $em, Request $req) + { + $required_params = [ + 'name', + 'address', + 'longitude', + 'latitude', + 'landmark', + ]; + $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 the information + $name = $req->request->get('name'); + $address = $req->request->get('address'); + $lng = $req->request->get('longitude'); + $lat = $req->request->get('latitude'); + $landmark = $req->request->get('landmark'); + + $loc_info = [ + 'address' => $address, + 'longitude' => $lng, + 'latitude' => $lat, + 'landmark' => $landmark, + ]; + + // check if customer already has existing metadata + $c_meta = $em->getRepository(CustomerMetadata::class)->findOneBy(['customer' => $cust]); + if ($c_meta == null) + { + // create new customer meta + $cust_meta = new CustomerMetadata(); + $cust_meta->setCustomer($cust); + $cust_meta->addMetaInfo($name, $loc_info); + + $em->persist($cust_meta); + } + else + { + // limit locations to 6. If more than 6, pop the first one out + // add location to existing customer meta + $meta_count = count($c_meta->getAllMetaInfo()); + + if ($meta_count >= 6) + $c_meta->popMetaInfo(); + + $c_meta->addMetaInfo($name, $loc_info); + } + + $em->flush(); + + return $res->getReturnResponse(); + } + + public function getLocations(EntityManagerInterface $em, Request $req) + { + $required_params = []; + $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 the customer meta for customer + $locations = []; + $cust_meta = $em->getRepository(CustomerMetadata::class)->findOneBy(['customer' => $cust]); + if ($cust_meta != null) + { + $locations[] = $cust_meta->getAllMetaInfo(); + } + + $data = [ + 'locations' => $locations, + ]; + + $res->setData($data); + + return $res->getReturnResponse(); + } + + public function removeVehicle($id, EntityManagerInterface $em, Request $req) + { + $required_params = []; + $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(); + } + + // find customer vehicle + $cv = $em->getRepository(CustomerVehicle::class)->find($id); + if ($cv == null) + { + $res->setError(true) + ->setErrorMessage('Invalid customer vehicle id'); + return $res->getReturnResponse(); + } + + // confirm that customer vehicle belongs to customer + if ($cv->getCustomer()->getID() != $cust->getID()) + { + $res->setError(true) + ->setErrorMessage('Vehicle does not belong to customer'); + return $res->getReturnResponse(); + } + + // we cannot remove a vehicle from customer if customer vehicle has already has JOs for it. + // instead we set the customer vehicle's flag_active to false + $cv->setActive(false); + $em->flush(); + + // response + return $res->getReturnResponse(); + } + + public function getLatestJobOrder(EntityManagerInterface $em, Request $req, RiderTracker $rt) + { + // check required parameters and api key + $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 the latest job order for customer + $latest_jo = $em->getRepository(JobOrder::class)->findOneBy(['customer' => $cust], ['id' => 'DESC']); + + $jo_data = null; + if ($latest_jo != null) + { + // TODO: clean the response up to just return what is needed + $jo_data = $this->generateLatestJobOrderData($req, $latest_jo, $rt); + } + + $data = [ + 'latest_job_order' => $jo_data, + ]; + + $res->setData($data); + + // response + return $res->getReturnResponse(); + } + + // commenting it out. Modify the getJOHistory instead to just get the fulfilled + // and cancelled job orders, since ongoing is not yet part of history + /* + public function getCompletedJobOrders(Request $req, EntityManagerInterface $em, RiderTracker $rt) + { + $required_params = []; + $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(); + } + + $completed_jos = $this->getCompletedJOs($cust, $em); + + // initialize data + $jo_data = []; + foreach ($completed_jos as $jo) + { + $jo_data[] = $this->generateJobOrderData($req, $jo, $rt); + } + + $data = [ + 'completed_job_orders' => $jo_data, + ]; + + $res->setData($data); + + return $res->getReturnResponse(); + } + + protected function getCompletedJOs($cust, EntityManagerInterface $em) + { + $completed_jos = $em->getRepository(JobOrder::class)->findBy([ + 'customer' => $cust, + 'status' => [JOStatus::CANCELLED, JOStatus::FULFILLED], + ], ['date_schedule' => 'desc']); + + return $completed_jos; + } + */ + protected function updateWarranty($res, $em, $rt, $trans, $req, $serial, $inv_filename = null, $wcard_filename = null, $logger, $log_data, $user_id, $action, $source) { @@ -4124,4 +4486,110 @@ class APIController extends Controller implements LoggedController return $time_selected; } + + protected function generateLatestJobOrderData($req, $jo, $rt) + { + $status = $jo->getStatus(); + + $dest = $jo->getCoordinates(); + + $jo_data = [ + 'id' => $jo->getID(), + 'date_create' => $jo->getDateCreate()->format('M d, Y'), + 'service_type' => $jo->getServiceType(), + 'destination' => [ + 'long' => $dest->getLongitude(), + 'lat' => $dest->getLatitude(), + ], + 'delivery_address' => $jo->getDeliveryAddress(), + 'delivery_instructions' => $jo->getDeliveryInstructions(), + 'jo_status' => $status, + 'status' => $this->generateAPIRiderStatus($status), + 'landmark' => $jo->getLandmark(), + ]; + + // customer vehicle and warranty + $cv = $jo->getCustomerVehicle(); + + // get latest warranty using plate number + $warranty = $this->findWarranty($cv->getPlateNumber()); + + $jo_data['customer_vehicle'] = [ + 'id' => $cv->getID(), + 'plate_number' => $cv->getPlateNumber(), + 'warranty' => $warranty, + ]; + + // customer information + $customer = $jo->getCustomer(); + $jo_data['customer'] = [ + 'first_name' => $customer->getFirstName(), + 'last_name' => $customer->getLastName(), + 'mobile_number' => $customer->getPhoneMobile(), + ]; + + // rider + $rider = $jo->getRider(); + if ($rider != null) + { + // default image url + $url_prefix = $req->getSchemeAndHttpHost(); + $image_url = $url_prefix . '/assets/images/user.gif'; + if ($rider->getImageFile() != null) + $image_url = $url_prefix . '/uploads/' . $rider->getImageFile(); + + $coord = $rt->getRiderLocation($rider->getID()); + + $jo_data['rider'] = [ + 'id' => $rider->getID(), + 'name' => $rider->getFullName(), + 'plate_num' => $rider->getPlateNumber(), + 'contact_num' => $rider->getContactNumber(), + 'image_url' => $image_url, + 'location' => [ + 'long' => $coord->getLongitude(), + 'lat' => $coord->getLatitude() + ] + ]; + } + else + { + $jo_data['rider'] = null; + } + + // invoice items + $items = []; + $jo_items = $jo->getInvoice()->getItems(); + foreach ($jo_items as $item) + { + $items[] = [ + 'id' => $item->getID(), + 'title' => $item->getTitle(), + 'qty' => $item->getQuantity(), + 'price' => $item->getPrice(), + ]; + } + + $jo_data['items'] = $items; + + + // dates depending on status + switch ($status) + { + case JOStatus::FULFILLED: + if ($jo->getDateFulfill() == null) + $jo_data['date_fulfilled'] = ''; + else + $jo_data['date_fulfilled'] = $jo->getDateFulfill()->format('M d, Y'); + break; + case JOStatus::CANCELLED: + $date_cancel = $jo->getDateCancel(); + if ($date_cancel == null) + $date_cancel = new DateTime(); + $jo_data['date_cancelled'] = $date_cancel->format('M d, Y'); + break; + } + + return $jo_data; + } } diff --git a/src/Entity/Customer.php b/src/Entity/Customer.php index 4af84d96..de2cd92e 100644 --- a/src/Entity/Customer.php +++ b/src/Entity/Customer.php @@ -222,6 +222,12 @@ class Customer */ protected $car_club_customer_hub; + // ratings made by customer + /** + * @ORM\OneToMany(targetEntity="RiderRating", mappedBy="customer") + */ + protected $ratings; + public function __construct() { $this->numbers = new ArrayCollection(); @@ -259,6 +265,8 @@ class Customer $this->date_create = new DateTime(); $this->create_source = 'unknown'; + + $this->ratings = new ArrayCollection(); } public function getID() diff --git a/src/Entity/CustomerMetadata.php b/src/Entity/CustomerMetadata.php new file mode 100644 index 00000000..5ef9d518 --- /dev/null +++ b/src/Entity/CustomerMetadata.php @@ -0,0 +1,87 @@ +meta_info = []; + } + + public function getID() + { + return $this->id; + } + + public function setCustomer(Customer $customer) + { + $this->customer = $customer; + return $this; + } + + public function getCustomer() + { + return $this->customer; + } + + public function addMetaInfo($id, $value) + { + $this->meta_info[$id] = $value; + return $this; + } + + public function getMetaInfo($id) + { + // return null if we don't have it + if (!isset($this->meta_info[$id])) + return null; + + return $this->meta_info[$id]; + } + + public function getAllMetaInfo() + { + return $this->meta_info; + } + + public function popMetaInfo() + { + if (count($this->meta_info) > 0) + { + array_shift($this->meta_info); + } + } +} diff --git a/src/Entity/JobOrder.php b/src/Entity/JobOrder.php index fcbe5ddc..eace43a1 100644 --- a/src/Entity/JobOrder.php +++ b/src/Entity/JobOrder.php @@ -365,6 +365,12 @@ class JobOrder */ protected $delivery_status; + // rider rating + /** + * @ORM\OneToOne(targetEntity="RiderRating", mappedBy="job_order") + */ + protected $rating; + public function __construct() { $this->date_create = new DateTime(); @@ -1050,4 +1056,8 @@ class JobOrder return $this->delivery_status; } + public function getRating() + { + return $this->rating; + } } diff --git a/src/Entity/Rider.php b/src/Entity/Rider.php index 34f49455..020393da 100644 --- a/src/Entity/Rider.php +++ b/src/Entity/Rider.php @@ -136,6 +136,11 @@ class Rider */ protected $api_user; + /** + * @ORM\OneToMany(targetEntity="RiderRating", mappedBy="rider") + */ + protected $ratings; + public function __construct() { $this->job_orders = new ArrayCollection(); @@ -150,6 +155,8 @@ class Rider $this->active_job_order = null; $this->current_job_order = null; $this->api_user = null; + + $this->ratings = new ArrayCollection(); } public function getID() diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index ba7125f0..8475484f 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -1045,10 +1045,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } } - $obj->fulfill(); - if (empty($error_array)) { + $obj->fulfill(); + // the event $event = new JOEvent(); $event->setDateHappen(new DateTime()) @@ -1134,6 +1134,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface if (!empty($phone_number)) $this->sendSMSToCustomer($phone_number); } + + return $error_array; } // cancel job order