From fdabca76758a8ea02814a47f0e14a50e2e1260e6 Mon Sep 17 00:00:00 2001 From: nfesta2023 <142601504+nfesta2023@users.noreply.github.com> Date: Sat, 27 Jan 2024 19:55:42 +0700 Subject: [PATCH] FES-48-adjust-restaurant-detailed-api (#45) * add distance and time delivery logic Co-authored-by: NHT --- src/dto/restaurant-detail.dto.ts | 2 + .../dto/get-restaurant-detail-request.dto.ts | 5 ++ .../dto/get-restaurant-detail-response.dto.ts | 79 +++++++++++++++++++ .../restaurant/restaurant.controller.ts | 36 ++++++++- src/feature/restaurant/restaurant.service.ts | 75 ++++++++++-------- 5 files changed, 162 insertions(+), 35 deletions(-) create mode 100644 src/feature/restaurant/dto/get-restaurant-detail-request.dto.ts create mode 100644 src/feature/restaurant/dto/get-restaurant-detail-response.dto.ts diff --git a/src/dto/restaurant-detail.dto.ts b/src/dto/restaurant-detail.dto.ts index ab71a78..8b9024e 100644 --- a/src/dto/restaurant-detail.dto.ts +++ b/src/dto/restaurant-detail.dto.ts @@ -18,4 +18,6 @@ export class RestaurantDetailDTO { having_vegeterian_food: boolean; unit: string; menu: FoodDTO[]; + distance_km: number; + delivery_time_s: number; } diff --git a/src/feature/restaurant/dto/get-restaurant-detail-request.dto.ts b/src/feature/restaurant/dto/get-restaurant-detail-request.dto.ts new file mode 100644 index 0000000..0e7492b --- /dev/null +++ b/src/feature/restaurant/dto/get-restaurant-detail-request.dto.ts @@ -0,0 +1,5 @@ +export class GetRestaurantDetailRequest { + restaurant_id: number; + lat: number; + long: number; +} diff --git a/src/feature/restaurant/dto/get-restaurant-detail-response.dto.ts b/src/feature/restaurant/dto/get-restaurant-detail-response.dto.ts new file mode 100644 index 0000000..9565895 --- /dev/null +++ b/src/feature/restaurant/dto/get-restaurant-detail-response.dto.ts @@ -0,0 +1,79 @@ +import { GeneralResponse } from 'src/dto/general-response.dto'; + +export class GetRestaurantDetailResponse extends GeneralResponse { + data: RestaurantDetailDTO; +} +interface RestaurantDetailDTO { + restaurant_id: number; + medias: MediaItem[]; + address: StandardAddress; + logo_img: string; + rating: number; + top_food: string; + promotion: string; + reviews: Review[]; + name: TextByLang[]; + specialty: TextByLang[]; + introduction: TextByLang[]; + review_total_count: number; + cutoff_time: string[]; + having_vegeterian_food: boolean; + unit: string; + menu: FoodDTO[]; + distance_km: number; + delivery_time_s: number; +} + +interface MediaItem { + type: string; + url: string; +} + +interface StandardAddress { + address_line: string; + ward: string; + district: string; + city: string; + country: string; + latitude: number; + longitude: number; +} + +interface Review { + food_rating_id: number; + score: number; + remarks: string; + reviewer?: string; +} + +interface TextByLang { + ISO_language_code: string; + text: string; +} + +interface FoodDTO { + id: number; + image: string; + top_label: string; + bottom_label: string; + name: TextByLang[]; + restaurant_name: TextByLang[]; + restaurant_id: number; + calorie_kcal: number; + rating: number; + distance_km: number; + delivery_time_s: number; + main_cooking_method: TextByLang[]; + ingredient_brief_vie: string; + ingredient_brief_eng: string; + price: number; + price_after_discount: number; + promotion: string; + cutoff_time: string; + preparing_time_s: number; + cooking_time_s: number; + quantity_available: number; + is_vegetarian: boolean; + cooking_schedule: string; + units_sold: number; +} diff --git a/src/feature/restaurant/restaurant.controller.ts b/src/feature/restaurant/restaurant.controller.ts index 1f52d5d..a37652e 100644 --- a/src/feature/restaurant/restaurant.controller.ts +++ b/src/feature/restaurant/restaurant.controller.ts @@ -1,7 +1,9 @@ -import { Controller, Inject } from '@nestjs/common'; +import { Controller, HttpException, Inject } from '@nestjs/common'; import { RestaurantService } from './restaurant.service'; import { MessagePattern } from '@nestjs/microservices'; import { FlagsmithService } from 'src/dependency/flagsmith/flagsmith.service'; +import { GetRestaurantDetailRequest } from './dto/get-restaurant-detail-request.dto'; +import { GetRestaurantDetailResponse } from './dto/get-restaurant-detail-response.dto'; @Controller() export class RestaurantController { @@ -11,7 +13,33 @@ export class RestaurantController { ) {} @MessagePattern({ cmd: 'get_restaurant_details' }) - async getRestaurantDetails(restaurant_id: number) { - return await this.restaurantService.getRestaurantDetails(restaurant_id); - } + async getRestaurantDetails( + data: GetRestaurantDetailRequest, + ): Promise { + const { restaurant_id, lat, long } = data; + const res = new GetRestaurantDetailResponse(200, ''); + try { + const restaurantDetail = + await this.restaurantService.getRestaurantDetailsFromEndPoint( + restaurant_id, + lat, + long, + ); + res.statusCode = 200; + res.message = 'Getting Restaurant Details Successfully'; + res.data = restaurantDetail; + } catch (error) { + if (error instanceof HttpException) { + res.statusCode = error.getStatus(); + res.message = error.getResponse(); + res.data = null; + } else { + res.statusCode = 500; + res.message = error.toString(); + res.data = null; + } + } + + return res; + } // getRestaurantDetails } diff --git a/src/feature/restaurant/restaurant.service.ts b/src/feature/restaurant/restaurant.service.ts index 788b027..8737281 100644 --- a/src/feature/restaurant/restaurant.service.ts +++ b/src/feature/restaurant/restaurant.service.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common'; import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm'; import { Restaurant } from 'src/entity/restaurant.entity'; import { AhamoveService } from 'src/dependency/ahamove/ahamove.service'; @@ -6,7 +6,6 @@ import { DeliveryRestaurant, PriceRange, TextByLang } from 'src/type'; import { Between, EntityManager, In, Repository } from 'typeorm'; import { RestaurantDTO } from '../../dto/restaurant.dto'; import { FlagsmithService } from 'src/dependency/flagsmith/flagsmith.service'; -import { GeneralResponse } from 'src/dto/general-response.dto'; import { RestaurantDetailDTO } from 'src/dto/restaurant-detail.dto'; import { Media } from 'src/entity/media.entity'; import { CommonService } from '../common/common.service'; @@ -27,7 +26,7 @@ export class RestaurantService { async findAll(): Promise { return await this.restaurantRepo.find(); - } + } // end of findAll async getRestaurantByRadius( lat: number, @@ -59,14 +58,14 @@ export class RestaurantService { const restaurantsByRadius: DeliveryRestaurant[] = []; for (const restaurant of restaurants) { const timeAnhDistance = await this.ahamoveService.estimateTimeAndDistance( - { - lat: lat, - long: long, - }, { lat: Number(restaurant.address.latitude), long: Number(restaurant.address.longitude), }, + { + lat: lat, + long: long, + }, ); restaurantsByRadius.push({ ...restaurant, @@ -76,7 +75,7 @@ export class RestaurantService { }); } return restaurantsByRadius; - } + } // end of getRestaurantByRadius async getDeliveryRestaurantById( id: number, @@ -87,14 +86,14 @@ export class RestaurantService { where: { restaurant_id: id }, }); const timeAnhDistance = await this.ahamoveService.estimateTimeAndDistance( - { - lat: lat, - long: long, - }, { lat: Number(restaurant.address.latitude), long: Number(restaurant.address.longitude), }, + { + lat: lat, + long: long, + }, ); return { ...restaurant, @@ -102,7 +101,7 @@ export class RestaurantService { distance_km: timeAnhDistance.distance_km, delivery_time_s: timeAnhDistance.duration_s, }; - } + } // getDeliveryRestaurantById async getDeliveryRestaurantByListOfId( ids: number[], @@ -124,14 +123,14 @@ export class RestaurantService { } const timeAnhDistance = await this.ahamoveService.estimateTimeAndDistance( - { - lat: lat, - long: long, - }, { lat: Number(restaurant.address.latitude), long: Number(restaurant.address.longitude), }, + { + lat: lat, + long: long, + }, ); deliveryRestaurants.push({ ...restaurant, @@ -141,7 +140,7 @@ export class RestaurantService { }); } return deliveryRestaurants; - } + } // getDeliveryRestaurantByListOfId async convertIntoRestaurantDTO( restaurant: DeliveryRestaurant, @@ -185,10 +184,15 @@ export class RestaurantService { restaurantDTO.unit = restaurant.unit_obj.symbol; return restaurantDTO; - } + } // convertIntoRestaurantDTO - async getRestaurantDetails(restaurant_id: number) { - const result = new GeneralResponse(200, ''); + async getRestaurantDetailsFromEndPoint( + restaurant_id: number, + lat: number, + long: number, + ): Promise { + console.log('lat', lat); + console.log('long', long); const restaurant = await this.entityManager .createQueryBuilder(Restaurant, 'restaurant') @@ -209,9 +213,7 @@ export class RestaurantService { .getOne(); if (!restaurant) { - result.statusCode = 404; - result.message = 'Restaurant not found'; - return result; + throw new HttpException('Restaurant not found', HttpStatus.NOT_FOUND); } //Get medias @@ -249,6 +251,18 @@ export class RestaurantService { } cutoff_time.sort(); + //Calculate distance and time delivery + const timeAnhDistance = await this.ahamoveService.estimateTimeAndDistance( + { + lat: Number(restaurant.address.latitude), + long: Number(restaurant.address.longitude), + }, + { + lat: lat, + long: long, + }, + ); + //Mapping data with output const data: RestaurantDetailDTO = { restaurant_id: restaurant.restaurant_id, @@ -280,13 +294,12 @@ export class RestaurantService { having_vegeterian_food: having_vegeterian_food, unit: restaurant.unit_obj.symbol, menu: convertedMenuItems, + distance_km: timeAnhDistance.distance_km, + delivery_time_s: timeAnhDistance.duration_s, }; - result.statusCode = 200; - result.message = 'Getting Restaurant Details Successfully'; - result.data = data; - return result; - } + return data; + } // getRestaurantDetailsFromEndPoint async convertRestaurantExtToTextByLang( restaurant_ext: RestaurantExt[], @@ -319,7 +332,7 @@ export class RestaurantService { result.introduction.push(introductionByLang); } return result; - } + } // convertRestaurantExtToTextByLang async getAllMediaByRestaurantId(restaurant_id: number): Promise { const data = await this.entityManager @@ -333,5 +346,5 @@ export class RestaurantService { .orWhere('media.restaurant_id = :restaurant_id', { restaurant_id }) .getMany(); return data; - } + } // getAllMediaByRestaurantId }