import { HttpService } from "@nestjs/axios"; import { BadRequestException, HttpException, Injectable, Logger } from "@nestjs/common"; import { Inject } from "@nestjs/common"; import { AxiosError } from "axios"; import { catchError, firstValueFrom, throwError } from "rxjs"; import { IDmenuConfig } from "../../../configs/icons.config"; import { DMENU_CONFIG } from "../constants"; import { FindRestaurantsDto } from "../DTO/find-restaurants.dto"; import { SetupRestaurantDto } from "../DTO/create-restaurant.dto"; import { UpdateRestaurantDto } from "../DTO/update-restaurant.dto"; import { CreateMyRestaurantAdminDto } from "../DTO/create-restaurant-admin.dto"; import { PlanEnum, ISetupRestaurant, IExternalApiResponse } from "../interface/plan.interface"; import { SubscriptionsService } from "../../subscriptions/providers/subscriptions.service"; import { UsersService } from "../../users/providers/users.service"; import { SubscriptionMessage } from "../../../common/enums/message.enum"; @Injectable() export class RestaurantService { private readonly logger = new Logger(RestaurantService.name); constructor( @Inject(DMENU_CONFIG) private readonly config: IDmenuConfig, private readonly httpService: HttpService, private readonly subscriptionService: SubscriptionsService, private readonly usersService: UsersService, ) { } private getHeaders(): Record { const credentials = Buffer.from(`${this.config.username}:${this.config.password}`).toString("base64"); return { "Content-Type": "application/json", Authorization: `Basic ${credentials}`, }; } async findAll(queryDto: FindRestaurantsDto) { try { const params: Record = { page: queryDto.page || 1, limit: queryDto.limit || 10, orderBy: queryDto.orderBy || "createdAt", order: queryDto.order || "desc", }; if (queryDto.search) { params.search = queryDto.search; } if (queryDto.isActive !== undefined) { params.isActive = queryDto.isActive; } if (queryDto.plan) { params.plan = queryDto.plan; } const { data } = await firstValueFrom( this.httpService .get>(`${this.config.baseUrl}/super-admin/restaurants`, { params, headers: this.getHeaders(), }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to fetch restaurants: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return { restaurants: data.data, count: data.meta.total, paginate: true, }; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error fetching restaurants: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async getRestaurantById(id: string) { try { const { data } = await firstValueFrom( this.httpService .get(`${this.config.baseUrl}/super-admin/restaurants/${id}`, { headers: this.getHeaders(), }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to get restaurant by ID: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error getting restaurant by ID: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async createRestaurant(dto: SetupRestaurantDto, userId: string) { const { userSubscription } = await this.subscriptionService.getUserSubscriptionById(dto.userSubscriptionId, userId); if (!userSubscription) { throw new BadRequestException(SubscriptionMessage.USER_SUBS_NOT_FOUND); } const plan = userSubscription.plan.name.includes("دلیوری") ? PlanEnum.Premium : PlanEnum.Base; const user = await this.usersService.findOneById(userId) if (!user) { throw new BadRequestException("User Not found"); } const setupRestaurantDto: ISetupRestaurant = { name: userSubscription.businessName, slug: dto.slug, establishedYear: 1400, phone: user.user.phone, plan, subscriptionId: dto.userSubscriptionId, subscriptionEndDate: userSubscription.endDate.toISOString(), subscriptionStartDate: userSubscription.startDate.toISOString(), isActive: true }; try { const { data } = await firstValueFrom( this.httpService .post(`${this.config.baseUrl}/super-admin/restaurants`, setupRestaurantDto, { headers: this.getHeaders(), }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to create restaurant: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error creating restaurant: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async updateRestaurant(id: string, dto: UpdateRestaurantDto) { try { const { data } = await firstValueFrom( this.httpService .patch(`${this.config.baseUrl}/super-admin/restaurants/${id}`, dto, { headers: this.getHeaders(), }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to update restaurant: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error updating restaurant: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async getRestaurantSubscription(subscriptionId: string) { try { console.log('subscriptionId', subscriptionId) const { data } = await firstValueFrom( this.httpService .get(`${this.config.baseUrl}/super-admin/restaurants/subscription/${subscriptionId}`, { headers: this.getHeaders(), }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to get restaurant subscription: ${err.message}`, err.stack); return throwError(() => err); }), ), ); console.log('data', data) return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error getting restaurant subscription: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async getSmsCountByRestaurant(page: number, limit: number) { try { const { data } = await firstValueFrom( this.httpService .get(this.config.baseUrl + "/super-admin/notifications/sms-count", { params: { page, limit }, headers: this.getHeaders() }) .pipe( catchError((err: AxiosError) => { this.logger.error("error in getting SMS count by restaurant", err); return throwError(() => err); }), ), ); return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error("error in getSmsCountByRestaurant", error); throw error; } } async getSystemRoles() { try { const { data } = await firstValueFrom( this.httpService .get(`${this.config.baseUrl}/super-admin/system-roles`, { headers: this.getHeaders(), }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to get system roles: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error getting system roles: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async getRestaurantAdmins(restaurantId: string) { try { const { data } = await firstValueFrom( this.httpService .get(`${this.config.baseUrl}/super-admin/restaurants/${restaurantId}/admins`, { headers: this.getHeaders(), }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to get restaurant admins: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error getting restaurant admins: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async revokeRestaurantAdmin(restaurantId: string, adminId: string) { try { const { data } = await firstValueFrom( this.httpService .delete(`${this.config.baseUrl}/super-admin/restaurants/${restaurantId}/admins/${adminId}`, { headers: this.getHeaders(), data: {}, }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to revoke restaurant admin: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error revoking restaurant admin: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async assignRestaurantAdmin(restaurantId: string, dto: CreateMyRestaurantAdminDto) { try { const { data } = await firstValueFrom( this.httpService .post(`${this.config.baseUrl}/super-admin/restaurants/${restaurantId}/admins`, dto, { headers: this.getHeaders(), }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to assign restaurant admin: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return { ...data, }; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error assigning restaurant admin: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async upgradeSubscription(subscriptionId: string, newPlan: 'base' | 'premium', subscriptionEndDate: Date) { try { const { data } = await firstValueFrom( this.httpService .patch(`${this.config.baseUrl}/super-admin/restaurants/subscription/${subscriptionId}/upgrade`, { newPlan, subscriptionEndDate }, { headers: this.getHeaders(), }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to upgrade restaurant subscription: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error upgrading restaurant subscription: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async hardDeleteRestaurant(id: string) { try { const { data } = await firstValueFrom( this.httpService .delete(`${this.config.baseUrl}/super-admin/restaurants/${id}/hard-delete`, { headers: this.getHeaders(), data: {}, }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to hard delete restaurant: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error hard deleting restaurant: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } async directLogin(userSubscriptionId: string, userId: string) { try { // 1. Get userSubscription by id const user = await this.usersService.findOneById(userId) if (!user) { throw new BadRequestException("User Not found"); } // 2. Get phone from userSubscription const phone = user.user.phone if (!phone) { throw new BadRequestException("Phone number not found in user subscription"); } // 3. Get restaurant by subscription id const restaurant = await this.getRestaurantSubscription(userSubscriptionId); // 4. Get slug from restaurant const slug = restaurant.data.slug; if (!slug) { throw new BadRequestException("Restaurant slug not found"); } // 5. Login with phone and slug const { data } = await firstValueFrom( this.httpService .post(`${this.config.baseUrl}/super-admin/auth/direct-login`, { phone, slug, }, { headers: this.getHeaders(), }) .pipe( catchError((err: AxiosError) => { this.logger.error(`Failed to perform direct login: ${err.message}`, err.stack); return throwError(() => err); }), ), ); return data; } catch (error: unknown) { if (error instanceof AxiosError && error.response) { this.logger.error(`External API error response:`, error.response.data); const errorResponse = { ...error.response.data, message: error.response.data.error?.message || error.message, }; throw new HttpException(errorResponse, error.response.status); } this.logger.error(`Error performing direct login: ${error instanceof Error ? error.message : "Unknown error"}`); throw error; } } }