diff --git a/config/services.yaml b/config/services.yaml index 9d1ee14e..f8b30b8a 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -221,6 +221,17 @@ services: event: 'postPersist' entity: 'App\Entity\JobOrder' + App\EventListener\JobOrderJsonCacheListener: + arguments: + $json_cache: "@App\\Service\\JobOrderJsonCache" + tags: + - name: 'doctrine.orm.entity_listener' + event: 'postUpdate' + entity: 'App\Entity\JobOrder' + - name: 'doctrine.orm.entity_listener' + event: 'postRemove' + entity: 'App\Entity\JobOrder' + App\Service\JobOrderCache: arguments: $redis_prov: "@App\\Service\\RedisClientProvider" @@ -233,6 +244,11 @@ services: $loc_key: "%env(LOCATION_RIDER_ACTIVE_KEY)%" $status_key: "%env(STATUS_RIDER_KEY)%" + App\Service\JobOrderJsonCache: + arguments: + $redis_prov: "@App\\Service\\RedisClientProvider" + $jo_json_cache_key: "%env(JO_JSON_CACHE_KEY)%" + # inventory manager App\Service\InventoryManager: arguments: diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index 4fd4e30e..7267ccf9 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -48,6 +48,7 @@ use App\Service\HubDistributor; use App\Service\HubFilterLogger; use App\Service\HubFilteringGeoChecker; use App\Service\HashGenerator; +use App\Service\JobOrderJsonCache; use App\Entity\MobileSession; use App\Entity\Customer; @@ -1867,7 +1868,7 @@ class APIController extends Controller implements LoggedController } // we can't use param converter for now because we want to output the proper 404 - public function getJobOrderInfo($id, Request $req, EntityManagerInterface $em, RiderTracker $rt) + public function getJobOrderInfo($id, Request $req, EntityManagerInterface $em, RiderTracker $rt, JobOrderJsonCache $json_cache) { // check required parameters and api key $res = $this->checkParamsAndKey($req, $em, []); @@ -1884,16 +1885,46 @@ class APIController extends Controller implements LoggedController } // get job order data - $jo = $em->getRepository(JobOrder::class)->find($id); - if ($jo == null) + // find just the job order and selected fields + // find the JO in cache first + $jo_info = $this->findJobOrderFromCache($id, $json_cache); + + if (!empty($jo_info)) + { + // check if job order belongs to customer / user + if ($cust->getID() != $jo_info['customer_id']) + { + $res->setError(true) + ->setErrorMessage('No job order information found'); + return $res->getReturnResponse(); + } + + $jo_data = $jo_info['jo_data']; + $data = [ + 'job_order' => $jo_data, + ]; + + $res->setData($data); + return $res->getReturnResponse(); + } + + // not in cache, get the JO from the DB + $jo_info = $this->findJobOrderFromDB($id, $em); + + // check if not in db + if (empty($jo_info)) { $res->setError(true) ->setErrorMessage('No job order information found'); return $res->getReturnResponse(); } + // we already have customer from the mobile session + // get the rest of the needed information from invoice and rider rating and customer vehicle + $other_data = $this->findOtherData($jo_info, $id, $em); + // check if job order belongs to customer / user - if ($cust->getID() != $jo->getCustomer()->getID()) + if ($cust->getID() != $jo_info['customer_id']) { $res->setError(true) ->setErrorMessage('No job order information found'); @@ -1901,8 +1932,8 @@ class APIController extends Controller implements LoggedController } // put into job order data array - $jo_data = $this->generateJobOrderData($req, $jo, $rt); - + // $jo_data = $this->generateJobOrderData($req, $jo, $rt); + $jo_data = $this->createJobOrderData($req, $jo_info, $other_data, $cust, $rt, $json_cache); $data = [ 'job_order' => $jo_data @@ -4696,6 +4727,308 @@ class APIController extends Controller implements LoggedController return $jo_data; } + protected function createJobOrderData($req, $jo_data, $other_data, $cust, $rt, $json_cache) + { + $status = $jo_data['status']; + $jo_id = $jo_data['id']; + + // need to convert the date_create to DateTime then string with the correct format + $date_create = DateTime::createFromFormat('Y-m-d H:i:s', $jo_data['date_create']); + $str_date_create = $date_create->format('M d, Y'); + + $data = [ + 'id' => $jo_id, + 'date_create' => $str_date_create, + 'service_type' => $jo_data['service_type'], + 'destination' => [ + 'long' => $jo_data['longitude'], + 'lat' => $jo_data['latitude'], + ], + 'delivery_address' => $jo_data['delivery_address'], + 'delivery_instructions' => $jo_data['delivery_instructions'], + 'jo_status' => $status, + 'status' => $this->generateAPIRiderStatus($status), + ]; + + // get customer vehicle and warranty + $cv_data = $other_data['cv_data']; + $cv_id = $cv_data['id']; + $plate_number = $cv_data['plate_number']; + + $warranty = $this->findWarranty($plate_number); + + $data['customer_vehicle'] = [ + 'id' => $cv_id, + 'plate_number' => $plate_number, + 'warranty' => $warranty, + ]; + + // customer information + $data['customer'] = [ + 'first_name' => $cust->getFirstName(), + 'last_name' => $cust->getLastName(), + 'mobile_number' => $cust->getPhoneMobile(), + ]; + + // rider + $rider_data = $other_data['rider_data']; + if (empty($rider_data)) + $data['rider'] = null; + else + { + // default image url + $url_prefix = $req->getSchemeAndHttpHost(); + $image_url = $url_prefix . '/assets/images/user.gif'; + if ($rider_data['image_file'] != null) + $image_url = $url_prefix . '/uploads/' . $rider_data['image_file']; + + $coord = $rt->getRiderLocation($rider_data['id']); + + $data['rider'] = [ + 'id' => $rider_data['id'], + 'name' => $rider_data['name'], + 'plate_num' => $rider_data['plate_num'], + 'contact_num' => $rider_data['contact_num'], + 'image_url' => $image_url, + 'location' => [ + 'long' => $coord->getLongitude(), + 'lat' => $coord->getLatitude() + ] + ]; + + } + + // invoice items + $items = []; + $invoice_items = $other_data['invoice_items']; + foreach ($invoice_items as $item) + { + $items[] = [ + 'id' => $item['id'], + 'title' => $item['title'], + 'qty' => $item['qty'], + 'price' => $item['price'], + ]; + } + $data['items'] = $items; + + // dates depending on status + // need to convert the date_fulfill and date_cancel to DateTime then string with the correct format + $str_date_fulfill = ''; + $str_date_cancel = ''; + if ($jo_data['date_fulfill'] != null) + { + $date_fulfill = DateTime::createFromFormat('Y-m-d H:i:s', $jo_data['date_fulfill']); + $str_date_fulfill = $date_fulfill->format('M d, Y'); + } + if ($jo_data['date_cancel'] != null) + { + $date_cancel = DateTime::createFromFormat('Y-m-d H:i:s', $jo_data['date_cancel']); + $str_date_cancel = $date_cancel->format('M d, Y'); + } + + switch ($status) + { + case JOStatus::FULFILLED: + $data['date_fulfilled'] = $str_date_fulfill; + break; + case JOStatus::CANCELLED: + if (empty($str_date_cancel)) + { + $date_cancel = new DateTime(); + $data['date_cancelled'] = $date_cancel->format('M d, Y'); + } + else + $data['date_cancelled'] = $str_date_cancel; + + break; + } + + // need to put the jo data in json format to redis + $json_jo_data = json_encode($data); + $value = $cust->getID() . '|' . $json_jo_data; + + $json_cache->addJOJsonInfo($jo_id, $value); + + return $data; + } + + protected function findJobOrderFromCache($id, $json_cache) + { + $cache_data = []; + + $jo_in_cache = $json_cache->findJOJsonInfo($id); + if (!empty($jo_in_cache)) + { + // need to get customer id from the string + $j_array = explode('|', $jo_in_cache, 2); + + $cust_id = $j_array[0]; + $data = json_decode($j_array[1]); + + $cache_data = [ + 'customer_id' => $cust_id, + 'jo_data' => $data, + ]; + } + + return $cache_data; + } + + protected function findJobOrderFromDB($id, EntityManagerInterface $em) + { + // not in cache, get from database + $found_jo = []; + $conn = $em->getConnection(); + + $jo_sql = 'SELECT jo.date_create, jo.service_type, ST_x(jo.coordinates), ST_y(jo.coordinates), + jo.delivery_address, jo.delivery_instructions, jo.status, jo.rider_id, jo.customer_id, jo.cvehicle_id, + jo.date_fulfill, jo.date_cancel + FROM job_order jo WHERE jo.id = :id'; + $stmt = $conn->prepare($jo_sql); + $stmt->execute(['id' => $id]); + + $jo_results = $stmt->fetch(); + + if (!empty($jo_results)) + { + $found_jo = [ + 'id' => $id, + 'date_create' => $jo_results['date_create'], + 'date_fulfill' => $jo_results['date_fulfill'], + 'date_cancel' => $jo_results['date_cancel'], + 'service_type' => $jo_results['service_type'], + 'longitude' => $jo_results['ST_x(jo.coordinates)'], + 'latitude' => $jo_results['ST_y(jo.coordinates)'], + 'delivery_address' => $jo_results['delivery_address'], + 'delivery_instructions' => $jo_results['delivery_instructions'], + 'status' => $jo_results['status'], + 'rider_id' => $jo_results['rider_id'], + 'customer_id' => $jo_results['customer_id'], + 'cv_id' => $jo_results['cvehicle_id'], + ]; + } + + return $found_jo; + } + + protected function findOtherData($jo_info, $id, EntityManagerInterface $em) + { + $other_data = []; + + // need to find invoice items via invoice. so find invoice using id aka jo_id + $ii_data = $this->findInvoiceItems($id, $em); + + // need to find rider if any + $rider_id = $jo_info['rider_id']; + $r_data = []; + if ($rider_id != null) + { + $r_data = $this->findRider($rider_id, $em); + } + + // need to find customer vehicle using cvehicle_id from jo_info + $cv_id = $jo_info['cv_id']; + $cv_data = $this->findCustomerVehicleById($cv_id, $em); + + $other_data = [ + 'invoice_items' => $ii_data, + 'rider_data' => $r_data, + 'cv_data' => $cv_data, + ]; + + return $other_data; + } + + protected function findInvoiceItems($id, EntityManagerInterface $em) + { + $invoice_items = []; + + $conn = $em->getConnection(); + + // need to find invoice items via invoice. so find invoice using id aka jo_id + $inv_sql = 'SELECT i.id FROM invoice i WHERE i.job_order_id = :jo_id'; + $stmt = $conn->prepare($inv_sql); + $stmt->execute(array('jo_id' => $id)); + + $inv_results = $stmt->fetch(); + + if (empty($inv_results)) + return $invoice_items; + + $invoice_id = $inv_results['id']; + + // find invoice items using invoice id + $ii_sql = 'SELECT ii.id, ii.qty, ii.title, ii.price from invoice_item ii + WHERE ii.invoice_id = :invoice_id'; + $stmt = $conn->prepare($ii_sql); + $stmt->execute(array('invoice_id' => $invoice_id)); + + $ii_results = $stmt->fetchAll(); + + foreach ($ii_results as $ii_result) + { + $invoice_items[] = [ + 'id' => $ii_result['id'], + 'qty' => $ii_result['qty'], + 'title' => $ii_result['title'], + 'price' => $ii_result['price'], + ]; + } + + return $invoice_items; + } + + protected function findRider($id, EntityManagerInterface $em) + { + $rider_data = []; + + $conn = $em->getConnection(); + + $rider_sql = 'SELECT r.first_name, r.last_name, r.contact_num, r.image_file, r.plate_number + FROM rider r WHERE r.id = :id'; + $stmt = $conn->prepare($rider_sql); + $stmt->execute(['id' => $id]); + + $rider_result = $stmt->fetch(); + + if (!empty($rider_result)) + { + $rider_data = [ + 'id' => $id, + 'name' => $rider_result['first_name'] . ' ' . $rider_result['last_name'], + 'plate_num' => $rider_result['plate_number'], + 'contact_num' => $rider_result['contact_num'], + 'image_file' => $rider_result['image_file'], + ]; + } + + return $rider_data; + } + + protected function findCustomerVehicleById($id, EntityManagerInterface $em) + { + $cv_data = []; + + $conn = $em->getConnection(); + + $cv_sql = 'SELECT cv.plate_number FROM customer_vehicle cv WHERE cv.id = :id'; + $stmt = $conn->prepare($cv_sql); + $stmt->execute(['id' => $id]); + + $cv_result = $stmt->fetch(); + + if (!empty($cv_result)) + { + $cv_data = [ + 'id' => $id, + 'plate_number' => $cv_result['plate_number'], + ]; + } + + return $cv_data; + } + protected function normalizeString($string) { return trim(strtolower($string)); diff --git a/src/EventListener/JobOrderJsonCacheListener.php b/src/EventListener/JobOrderJsonCacheListener.php new file mode 100644 index 00000000..e2410468 --- /dev/null +++ b/src/EventListener/JobOrderJsonCacheListener.php @@ -0,0 +1,37 @@ +json_cache = $json_cache; + } + + // when a job order is updated + public function postUpdate(JobOrder $jo, LifecycleEventArgs $args) + { + // get JO id + $id = $jo->getID(); + + $this->json_cache->removeJOJsonInfo($id); + } + + // when a job order is deleted + public function postRemove(JobOrder $jo, LifecycleEventArgs $args) + { + // get JO id + $id = $jo->getID(); + + $this->json_cache->removeJOJsonInfo($id); + } +} diff --git a/src/Service/JobOrderJsonCache.php b/src/Service/JobOrderJsonCache.php new file mode 100644 index 00000000..2df2fa5b --- /dev/null +++ b/src/Service/JobOrderJsonCache.php @@ -0,0 +1,53 @@ +redis = $redis_prov->getRedisClient(); + $this->jo_json_cache_key = $jo_json_cache_key; + } + + public function addJOJsonInfo($jo_id, $jo_data) + { + $key = $jo_id; + + $this->redis->hset($this->jo_json_cache_key, $key, $jo_data); + } + + public function findJOJsonInfo($jo_id) + { + $jo_data = ''; + + $key = $jo_id; + + // check if JO id is in redis hash + $is_exist = $this->redis->hexists($this->jo_json_cache_key, $key); + if ($is_exist) + { + // get the data + $jo_data = $this->redis->hget($this->jo_json_cache_key, $key); + } + + return $jo_data; + } + + public function removeJOJsonInfo($jo_id) + { + $key = $jo_id; + + // check if JO id is in redis hash + $is_exist = $this->redis->hexists($this->jo_json_cache_key, $key); + if ($is_exist) + { + $this->redis->hdel($this->jo_json_cache_key, $key); + } + } +}