From 1802b05e74d948adc9c09f816971182674214795 Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Mon, 22 Dec 2025 19:12:03 +0330 Subject: [PATCH] farsi messages --- src/common/enums/message.enum.ts | 108 +++++++ .../cart/providers/cart-item.service.ts | 5 +- .../cart/providers/cart-validation.service.ts | 37 ++- src/modules/cart/providers/cart.service.ts | 13 +- .../delivery/providers/delivery.service.ts | 9 +- .../controllers/notifications.controller.ts | 9 +- .../orders/listeners/order.listeners.ts | 299 +++++++++--------- .../orders/providers/orders.service.ts | 43 ++- .../pager/controllers/pager.controller.ts | 3 +- .../payments/gateways/zarinpal.gateway.ts | 15 +- .../payments/listeners/payment.listeners.ts | 15 +- .../services/payment-method.service.ts | 5 +- .../payments/services/payments.service.ts | 29 +- .../users/controllers/users.controller.ts | 5 +- 14 files changed, 365 insertions(+), 230 deletions(-) diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index 27315bd..8fabe7e 100755 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -66,6 +66,10 @@ export const enum AuthMessage { TOKEN_MISSED_OR_EXPIRED = 'توکن مفقود یا منقضی شده است', OLD_PASSWORD_REQUIRED = 'رمز عبور قبلی الزامی است', PASSWORD_CHANGE_FAILED = 'تغییر رمز عبور با مشکل روبرد شد', + SLUG_REQUIRED = 'اسلاگ الزامی است', + INVALID_TOKEN_PAYLOAD = 'محتویات توکن نامعتبر است', + INVALID_SLUG = 'اسلاگ نامعتبر است', + INVALID_OR_EXPIRED_TOKEN = 'توکن نامعتبر یا منقضی شده است', } export const enum FoodMessage { NOT_FOUND = 'غذایی با این مشخصات یافت نشد', @@ -579,6 +583,12 @@ export const enum NotificationMessage { NEW_EMAIL_MESSAGE = 'یک ایمیل جدید با موضوع [subject] دریافت شد', CHANGE_PASSWORD_MESSAGE = 'رمز عبور شما با موفقیت تغییر کرد', CHANGE_PASSWORD = 'تغییر رمز عبور', + NOT_FOUND = 'اعلان یافت نشد', + READ_SUCCESS = 'اعلان با موفقیت خوانده شد', + ORDER_CREATED = 'سفارش جدید ایجاد شد', + ORDER_STATUS_CHANGED = 'وضعیت سفارش تغییر کرد', + PAYMENT_SUCCESS = 'پرداخت با موفقیت انجام شد', + PAGER_CREATED = 'پیج جدید ایجاد شد', } export const enum SettingMessageEnum { @@ -664,3 +674,101 @@ export const enum GroupMessage { NOT_UPDATED = 'به‌روزرسانی گروه آیکون با خطا مواجه شد', NOT_DELETED = 'حذف گروه آیکون با خطا مواجه شد', } + +export const enum OrderMessage { + NOT_FOUND = 'سفارش یافت نشد', + PAYMENT_METHOD_MISSING = 'روش پرداخت سفارش مشخص نشده است', + INVALID_STATUS_TRANSITION = 'انتقال وضعیت نامعتبر است', + CART_EMPTY = 'سبد خرید خالی است. لطفا قبل از ایجاد سفارش، آیتم‌هایی به سبد اضافه کنید', + DELIVERY_METHOD_NOT_FOUND = 'روش ارسال یافت نشد', + PAYMENT_METHOD_REQUIRED = 'روش پرداخت الزامی است. لطفا قبل از ایجاد سفارش، روش پرداخت را تنظیم کنید', + USER_NOT_FOUND = 'کاربر یافت نشد', + RESTAURANT_NOT_FOUND = 'رستوران یافت نشد', + DELIVERY_NOT_FOUND = 'روش ارسال یافت نشد', + MIN_ORDER_AMOUNT_NOT_MET = 'مبلغ سفارش کمتر از حداقل مجاز برای این روش ارسال است', + TABLE_NUMBER_REQUIRED = 'شماره میز برای سفارش در محل الزامی است', + ADDRESS_REQUIRED = 'آدرس الزامی است. لطفا قبل از ایجاد سفارش، آدرس تحویل را تنظیم کنید', + CAR_ADDRESS_REQUIRED = 'آدرس خودرو الزامی است. لطفا قبل از ایجاد سفارش، آدرس خودرو را تنظیم کنید', + PAYMENT_METHOD_NOT_FOUND = 'روش پرداخت یافت نشد', + PAYMENT_METHOD_NOT_ENABLED = 'روش پرداخت برای این رستوران فعال نیست', + FOOD_NOT_FOUND = 'غذا یافت نشد', + FOOD_NOT_BELONGS_TO_RESTAURANT = 'غذا به این رستوران تعلق ندارد', +} + +export const enum CartMessage { + TABLE_NUMBER_REQUIRED = 'شماره میز برای سفارش در محل الزامی است', + CAR_ADDRESS_REQUIRED = 'آدرس خودرو برای تحویل به خودرو الزامی است', + ADDRESS_REQUIRED = 'آدرس برای تحویل پیک الزامی است', + NOT_FOUND = 'سبد خرید یافت نشد', + COUPON_NOT_FOUND = 'کوپن یافت نشد', + FOOD_NOT_FOUND = 'غذا یافت نشد', + FOOD_NOT_BELONGS_TO_RESTAURANT = 'غذا به این رستوران تعلق ندارد', + FOOD_NO_INVENTORY = 'غذا موجودی ندارد', + INSUFFICIENT_STOCK = 'موجودی کافی نیست', + USER_NOT_FOUND = 'کاربر یافت نشد', + ADDRESS_NOT_FOUND = 'آدرس یافت نشد', + RESTAURANT_NOT_FOUND = 'رستوران یافت نشد', + ADDRESS_NOT_BELONGS_TO_USER = 'آدرس به کاربر فعلی تعلق ندارد', + ADDRESS_NO_COORDINATES = 'آدرس مختصات جغرافیایی ندارد', + ADDRESS_OUTSIDE_SERVICE_AREA = 'آدرس خارج از محدوده سرویس رستوران است', + DELIVERY_METHOD_NOT_FOUND = 'روش ارسال یافت نشد', + DELIVERY_METHOD_NOT_ENABLED = 'روش ارسال برای این رستوران فعال نیست', + PAYMENT_METHOD_NOT_FOUND = 'روش پرداخت یافت نشد', + PAYMENT_METHOD_NOT_ENABLED = 'روش پرداخت برای این رستوران فعال نیست', + WALLET_NOT_FOUND = 'کیف پول کاربر یافت نشد', + WALLET_INSUFFICIENT = 'موجودی کیف پول کافی نیست', + COUPON_MAX_USES_REACHED = 'حداکثر استفاده از کوپن به پایان رسیده است', + ITEM_NOT_FOUND = 'آیتم در سبد خرید یافت نشد', +} + +export const enum PaymentMessage { + UNSUPPORTED_PAYMENT_METHOD = 'روش پرداخت پشتیبانی نمی‌شود', + ORDER_NOT_FOUND = 'سفارش یافت نشد', + AMOUNT_MUST_BE_GREATER_THAN_ZERO = 'مبلغ باید بیشتر از صفر باشد', + PAYMENT_METHOD_NOT_FOUND = 'روش پرداخت یافت نشد', + GATEWAY_REQUIRED = 'درگاه پرداخت برای پرداخت آنلاین الزامی است', + MERCHANT_ID_REQUIRED = 'شناسه مرچنت برای پرداخت آنلاین الزامی است', + RESTAURANT_DOMAIN_REQUIRED = 'دامنه رستوران برای پرداخت آنلاین الزامی است', + WALLET_NOT_FOUND = 'کیف پول کاربر یافت نشد', + INSUFFICIENT_WALLET_BALANCE = 'موجودی کیف پول کافی نیست', + PAYMENT_NOT_FOUND = 'پرداخت یافت نشد', + INVALID_PAYMENT_CONFIGURATION = 'پیکربندی پرداخت نامعتبر است', + PAYMENT_METHOD_NOT_CASH = 'روش پرداخت نقدی نیست', + PAYMENT_ALREADY_PAID = 'پرداخت قبلا انجام شده است', + EXISTING_PENDING_PAYMENT_MISMATCH = 'پرداخت در انتظار موجود با روش پرداخت سفارش مطابقت ندارد', + ZARINPAL_INVALID_RESPONSE = 'پاسخ نامعتبر از API زرین‌پال', + ZARINPAL_PAYMENT_REQUEST_ERROR = 'خطا در درخواست پرداخت زرین‌پال', + ZARINPAL_VERIFY_ERROR = 'خطا در تایید پرداخت زرین‌پال', + GATEWAY_ERROR = 'خطا در اتصال به درگاه پرداخت', +} + +export const enum DeliveryMessage { + RESTAURANT_NOT_FOUND = 'رستوران یافت نشد', + DELIVERY_METHOD_NOT_FOUND = 'روش ارسال یافت نشد', +} + +export const enum InventoryMessage { + AVAILABLE_STOCK_EXCEEDS_TOTAL = 'موجودی موجود نمی‌تواند از موجودی کل بیشتر باشد', + FOOD_NOT_FOUND = 'غذا یافت نشد', + FOOD_NOT_BELONGS_TO_RESTAURANT = 'غذا به این رستوران تعلق ندارد', + RESTAURANT_NOT_FOUND = 'رستوران یافت نشد', + FOODS_NOT_FOUND = 'غذاها یافت نشدند', +} + + +export const enum PagerMessage { + CREATED_SUCCESS = 'درخواست پیج با موفقیت ایجاد شد', +} + +export const enum UserSuccessMessage { + ADDRESS_DELETED_SUCCESS = 'آدرس با موفقیت حذف شد', + SCORE_CONVERTED_SUCCESS = 'امتیاز با موفقیت به کیف پول تبدیل شد', +} + +export const enum ContactMessage { + NOT_FOUND = 'تماس یافت نشد', + CREATED = 'تماس با موفقیت ثبت شد', + UPDATED = 'تماس با موفقیت به‌روزرسانی شد', + DELETED = 'تماس با موفقیت حذف شد', +} + diff --git a/src/modules/cart/providers/cart-item.service.ts b/src/modules/cart/providers/cart-item.service.ts index f6963cc..d513016 100644 --- a/src/modules/cart/providers/cart-item.service.ts +++ b/src/modules/cart/providers/cart-item.service.ts @@ -3,6 +3,7 @@ import { Food } from '../../foods/entities/food.entity'; import { Cart, CartItem } from '../interfaces/cart.interface'; import { CartValidationService } from './cart-validation.service'; import { CartCalculationService } from './cart-calculation.service'; +import { CartMessage } from 'src/common/enums/message.enum'; @Injectable() export class CartItemService { @@ -83,7 +84,7 @@ export class CartItemService { removeItemOrFail(cart: Cart, foodId: string): void { const itemIndex = this.getItemIndex(cart, foodId); if (itemIndex < 0) { - throw new NotFoundException(`Item with food ID ${foodId} not found in cart`); + throw new NotFoundException(CartMessage.ITEM_NOT_FOUND); } cart.items.splice(itemIndex, 1); } @@ -94,7 +95,7 @@ export class CartItemService { async decrementOrRemoveItem(cart: Cart, foodId: string): Promise { const itemIndex = this.getItemIndex(cart, foodId); if (itemIndex < 0) { - throw new NotFoundException(`Item with food ID ${foodId} not found in cart`); + throw new NotFoundException(CartMessage.ITEM_NOT_FOUND); } const existingItem = cart.items[itemIndex]; diff --git a/src/modules/cart/providers/cart-validation.service.ts b/src/modules/cart/providers/cart-validation.service.ts index d57d665..cf79146 100644 --- a/src/modules/cart/providers/cart-validation.service.ts +++ b/src/modules/cart/providers/cart-validation.service.ts @@ -13,6 +13,7 @@ import { OrderStatus } from '../../orders/interface/order.interface'; import { Cart } from '../interfaces/cart.interface'; import { GeographicUtils } from '../utils/geographic.utils'; import { MealType } from '../../foods/interface/food.interface'; +import { CartMessage } from 'src/common/enums/message.enum'; @Injectable() export class CartValidationService { @@ -24,15 +25,15 @@ export class CartValidationService { async validateAndGetFood(foodId: string, restaurantId: string, quantity: number): Promise { const food = await this.em.findOne(Food, { id: foodId }, { populate: ['restaurant', 'inventory'] }); if (!food) { - throw new NotFoundException(`Food with ID ${foodId} not found`); + throw new NotFoundException(CartMessage.FOOD_NOT_FOUND); } if (food.restaurant.id !== restaurantId) { - throw new BadRequestException(`Food ${food.title || food.id} does not belong to restaurant ${restaurantId}`); + throw new BadRequestException(CartMessage.FOOD_NOT_BELONGS_TO_RESTAURANT); } if (!food.inventory) { - throw new BadRequestException(`The food ${food.title || food.id} does not have inventory`); + throw new BadRequestException(CartMessage.FOOD_NO_INVENTORY); } this.validateStock(food, quantity); @@ -45,7 +46,7 @@ export class CartValidationService { validateStock(food: Food, quantity: number): void { const availableStock = food.inventory!.availableStock; if (availableStock < quantity) { - throw new BadRequestException(`Insufficient stock for food ${food.title}. Available: ${availableStock}`); + throw new BadRequestException(CartMessage.INSUFFICIENT_STOCK); } } @@ -55,7 +56,7 @@ export class CartValidationService { async getUserOrFail(userId: string): Promise { const user = await this.em.findOne(User, { id: userId }); if (!user) { - throw new NotFoundException(`User with ID ${userId} not found`); + throw new NotFoundException(CartMessage.USER_NOT_FOUND); } return user; } @@ -66,7 +67,7 @@ export class CartValidationService { async getUserAddressOrFail(addressId: string): Promise { const address = await this.em.findOne(UserAddress, { id: addressId }, { populate: ['user'] }); if (!address) { - throw new NotFoundException(`Address with ID ${addressId} not found`); + throw new NotFoundException(CartMessage.ADDRESS_NOT_FOUND); } return address; } @@ -77,7 +78,7 @@ export class CartValidationService { async getFoodOrFail(foodId: string): Promise { const food = await this.em.findOne(Food, { id: foodId }); if (!food) { - throw new NotFoundException(`Food with ID ${foodId} not found`); + throw new NotFoundException(CartMessage.FOOD_NOT_FOUND); } return food; } @@ -88,7 +89,7 @@ export class CartValidationService { async getRestaurantOrFail(restaurantId: string): Promise { const restaurant = await this.em.findOne(Restaurant, { id: restaurantId }); if (!restaurant) { - throw new NotFoundException('Restaurant not found'); + throw new NotFoundException(CartMessage.RESTAURANT_NOT_FOUND); } return restaurant; } @@ -98,7 +99,7 @@ export class CartValidationService { */ validateAddressOwnership(address: UserAddress, userId: string): void { if (address.user.id !== userId) { - throw new BadRequestException('Address does not belong to the current user'); + throw new BadRequestException(CartMessage.ADDRESS_NOT_BELONGS_TO_USER); } } @@ -133,7 +134,7 @@ export class CartValidationService { ); if (!GeographicUtils.isPointInPolygon(point, polygon)) { - throw new BadRequestException('Address is outside the restaurant service area'); + throw new BadRequestException(CartMessage.ADDRESS_OUTSIDE_SERVICE_AREA); } } @@ -168,12 +169,10 @@ export class CartValidationService { { populate: ['restaurant'] }, ); if (!deliveryMethod) { - throw new NotFoundException( - `Delivery method with ID ${deliveryMethodId} not found for restaurant ${restaurantId}`, - ); + throw new NotFoundException(CartMessage.DELIVERY_METHOD_NOT_FOUND); } if (!deliveryMethod.enabled) { - throw new BadRequestException('Delivery method is not enabled for this restaurant'); + throw new BadRequestException(CartMessage.DELIVERY_METHOD_NOT_ENABLED); } return deliveryMethod; } @@ -207,10 +206,10 @@ export class CartValidationService { { populate: ['restaurant'] }, ); if (!paymentMethod) { - throw new NotFoundException(`Payment method with ID ${paymentMethodId} not found for restaurant ${restaurantId}`); + throw new NotFoundException(CartMessage.PAYMENT_METHOD_NOT_FOUND); } if (!paymentMethod.enabled) { - throw new BadRequestException('Payment method is not enabled for this restaurant'); + throw new BadRequestException(CartMessage.PAYMENT_METHOD_NOT_ENABLED); } return paymentMethod; } @@ -225,11 +224,11 @@ export class CartValidationService { }); if (!wallet) { - throw new BadRequestException('User wallet not found'); + throw new BadRequestException(CartMessage.WALLET_NOT_FOUND); } if (wallet.wallet < amount) { - throw new BadRequestException('User wallet is not enough'); + throw new BadRequestException(CartMessage.WALLET_INSUFFICIENT); } } @@ -247,7 +246,7 @@ export class CartValidationService { }); if (ordersThatUsedTheCouponCount >= maxUsesPerUser) { - throw new BadRequestException(`You have reached the maximum number of uses (${maxUsesPerUser}) for this coupon`); + throw new BadRequestException(CartMessage.COUPON_MAX_USES_REACHED); } } diff --git a/src/modules/cart/providers/cart.service.ts b/src/modules/cart/providers/cart.service.ts index 7010c36..e791c62 100644 --- a/src/modules/cart/providers/cart.service.ts +++ b/src/modules/cart/providers/cart.service.ts @@ -12,6 +12,7 @@ import { CartValidationService } from './cart-validation.service'; import { CartCalculationService } from './cart-calculation.service'; import { CartItemService } from './cart-item.service'; import { SetCarDeliveryDto } from '../dto/set-car-delivery.dto'; +import { CartMessage } from 'src/common/enums/message.enum'; @Injectable() export class CartService { @@ -44,7 +45,7 @@ export class CartService { case DeliveryMethodEnum.DineIn: // DineIn requires table number and clears incompatible fields if (!tableNumber) { - throw new BadRequestException('Table number is required for dine-in orders'); + throw new BadRequestException(CartMessage.TABLE_NUMBER_REQUIRED); } this.clearFieldsIncompatibleWithDeliveryMethod(cart, DeliveryMethodEnum.DineIn); cart.tableNumber = tableNumber; @@ -58,7 +59,7 @@ export class CartService { case DeliveryMethodEnum.DeliveryCar: // DeliveryCar requires carAddress and clears incompatible fields if (!carAddress) { - throw new BadRequestException('Car address is required for car delivery'); + throw new BadRequestException(CartMessage.CAR_ADDRESS_REQUIRED); } this.clearFieldsIncompatibleWithDeliveryMethod(cart, DeliveryMethodEnum.DeliveryCar); const user = await this.validationService.getUserOrFail(userId); @@ -73,7 +74,7 @@ export class CartService { case DeliveryMethodEnum.DeliveryCourier: // DeliveryCourier requires addressId and clears incompatible fields if (!addressId) { - throw new BadRequestException('Address is required for courier delivery'); + throw new BadRequestException(CartMessage.ADDRESS_REQUIRED); } this.clearFieldsIncompatibleWithDeliveryMethod(cart, DeliveryMethodEnum.DeliveryCourier); const address = await this.validationService.getUserAddressOrFail(addressId); @@ -167,7 +168,7 @@ export class CartService { async findOneOrFail(userId: string, restaurantId: string): Promise { const cart = await this.cartRepository.findByUserAndRestaurant(userId, restaurantId); if (!cart) { - throw new NotFoundException('Cart not found'); + throw new NotFoundException(CartMessage.NOT_FOUND); } return cart; } @@ -229,11 +230,11 @@ export class CartService { ); if (!valid) { - throw new BadRequestException(message || 'Invalid coupon code'); + throw new BadRequestException(message || CartMessage.COUPON_NOT_FOUND); } if (!coupon) { - throw new BadRequestException('Coupon not found'); + throw new BadRequestException(CartMessage.COUPON_NOT_FOUND); } // Check maxUsesPerUser limit by counting how many orders this user has with this coupon diff --git a/src/modules/delivery/providers/delivery.service.ts b/src/modules/delivery/providers/delivery.service.ts index 001cee0..b9b266c 100644 --- a/src/modules/delivery/providers/delivery.service.ts +++ b/src/modules/delivery/providers/delivery.service.ts @@ -6,6 +6,7 @@ import { CreateDeliveryDto } from '../dto/create-delivery.dto'; import { UpdateDeliveryDto } from '../dto/update-delivery.dto'; import { RestRepository } from '../../restaurants/repositories/rest.repository'; import { DeliveryMethodEnum } from '../interface/delivery'; +import { DeliveryMessage } from 'src/common/enums/message.enum'; @Injectable() export class DeliveryService { @@ -18,7 +19,7 @@ export class DeliveryService { async create(restId: string, createDto: CreateDeliveryDto): Promise { const restaurant = await this.restRepository.findOne({ id: restId }); if (!restaurant) { - throw new NotFoundException(`رستوران با شناسه ${restId} یافت نشد.`); + throw new NotFoundException(DeliveryMessage.RESTAURANT_NOT_FOUND); } // Check if the delivery method with the same name already exists for this restaurant @@ -60,7 +61,7 @@ export class DeliveryService { }); if (!delivery) { - throw new NotFoundException(`روش ارسال با شناسه ${deliveryId} برای رستوران با شناسه ${restId} یافت نشد.`); + throw new NotFoundException(DeliveryMessage.DELIVERY_METHOD_NOT_FOUND); } return delivery; @@ -73,7 +74,7 @@ export class DeliveryService { }); if (!delivery) { - throw new NotFoundException(`روش ارسال با شناسه ${deliveryId} برای رستوران با شناسه ${restId} یافت نشد.`); + throw new NotFoundException(DeliveryMessage.DELIVERY_METHOD_NOT_FOUND); } // If method is being updated, check for conflicts @@ -102,7 +103,7 @@ export class DeliveryService { }); if (!delivery) { - throw new NotFoundException(`روش ارسال با شناسه ${deliveryId} برای رستوران با شناسه ${restId} یافت نشد.`); + throw new NotFoundException(DeliveryMessage.DELIVERY_METHOD_NOT_FOUND); } await this.em.removeAndFlush(delivery); diff --git a/src/modules/notifications/controllers/notifications.controller.ts b/src/modules/notifications/controllers/notifications.controller.ts index c396bac..086d54f 100644 --- a/src/modules/notifications/controllers/notifications.controller.ts +++ b/src/modules/notifications/controllers/notifications.controller.ts @@ -9,6 +9,7 @@ import { RestId } from '../../../common/decorators/rest-id.decorator'; import { UpdatePreferenceDto } from '../dto/update-preference.dto'; import { AdminId } from 'src/common/decorators/admin-id.decorator'; import { API_HEADER_SLUG } from 'src/common/constants/index'; +import { NotificationMessage } from 'src/common/enums/message.enum'; @ApiTags('notifications') @Controller() @@ -64,7 +65,7 @@ export class NotificationsController { @ApiParam({ name: 'id', description: 'Notification ID' }) async readNotificationUser(@RestId() restaurantId: string, @Param('id') id: string, @UserId() userId: string) { await this.notificationService.readNotificationAsUser(id, userId, restaurantId); - return { message: 'Notification read successfully' }; + return { message: NotificationMessage.READ_SUCCESS }; } @UseGuards(AuthGuard) @@ -73,7 +74,7 @@ export class NotificationsController { @ApiOperation({ summary: 'Read all notification ' }) async readAllNotificationUser(@RestId() restaurantId: string, @UserId() userId: string) { await this.notificationService.readAllNotifsAsUser(userId, restaurantId); - return { message: 'Notification read successfully' }; + return { message: NotificationMessage.READ_SUCCESS }; } /* ***************** Admin Endpoints ***************** */ @@ -116,7 +117,7 @@ export class NotificationsController { @ApiParam({ name: 'id', description: 'Notification ID' }) async readNotificationAdmin(@RestId() restaurantId: string, @AdminId() adminId: string, @Param('id') id: string) { await this.notificationService.readNotificationAdmin(id, adminId, restaurantId); - return { message: 'Notification read successfully' }; + return { message: NotificationMessage.READ_SUCCESS }; } @UseGuards(AdminAuthGuard) @@ -125,7 +126,7 @@ export class NotificationsController { @ApiOperation({ summary: 'Read all notification ' }) async readAllNotificationAdmin(@RestId() restaurantId: string, @AdminId() adminId: string, @Param('id') id: string) { await this.notificationService.readAllNotifsAsAdmin(adminId, restaurantId); - return { message: 'Notification read successfully' }; + return { message: NotificationMessage.READ_SUCCESS }; } @UseGuards(AdminAuthGuard) diff --git a/src/modules/orders/listeners/order.listeners.ts b/src/modules/orders/listeners/order.listeners.ts index c724825..af79603 100644 --- a/src/modules/orders/listeners/order.listeners.ts +++ b/src/modules/orders/listeners/order.listeners.ts @@ -24,6 +24,21 @@ export class OrderListeners { this.orderStatusChangedSmsTemplateId = this.configService.get('SMS_PATTERN_ORDER_STATUS_CHANGE') ?? '123'; } + private getStatusFarsi(status: OrderStatus): string { + const statusMap: Record = { + [OrderStatus.PENDING_PAYMENT]: 'در انتظار پرداخت', + [OrderStatus.PAID]: 'پرداخت شده', + [OrderStatus.CONFIRMED]: 'تایید شده', + [OrderStatus.PREPARING]: 'در حال آماده‌سازی', + [OrderStatus.DELIVERED_TO_RECEPTIONIST]: 'تحویل به پذیرش', + [OrderStatus.DELIVERED_TO_WAITER]: 'تحویل به گارسون', + [OrderStatus.SHIPPED]: 'ارسال شده', + [OrderStatus.COMPLETED]: 'تکمیل شده', + [OrderStatus.CANCELED]: 'لغو شده', + }; + return statusMap[status] || status; + } + @OnEvent(OrderCreatedEvent.name) async handleOrderCreated(event: OrderCreatedEvent) { try { @@ -39,7 +54,7 @@ export class OrderListeners { restaurantId: event.restaurantId, message: { title: NotifTitleEnum.ORDER_CREATED, - content: `Order ${event.orderNumber} with ${event.total} has been created successfully`, + content: `سفارش شماره ${event.orderNumber} با مبلغ ${event.total} تومان با موفقیت ایجاد شد`, sms: { templateId: this.orderCreatedSmsTemplateId, parameters: { @@ -48,8 +63,8 @@ export class OrderListeners { }, }, pushNotif: { - title: `Order ${event.orderNumber} with ${event.total} has been created successfully`, - content: `Order ${event.orderNumber} with ${event.total} has been created successfully`, + title: `سفارش جدید`, + content: `سفارش شماره ${event.orderNumber} با مبلغ ${event.total} تومان با موفقیت ایجاد شد`, icon: `/`, action: { type: NotifTitleEnum.ORDER_CREATED, @@ -95,7 +110,7 @@ export class OrderListeners { restaurantId: event.restaurantId, message: { title: NotifTitleEnum.ORDER_STATUS_CHANGED, - content: `Order #${event.orderNumber} status is changed to ${event.newStatus} .`, + content: `وضعیت سفارش شماره ${event.orderNumber} به ${this.getStatusFarsi(event.newStatus)} تغییر کرد`, sms: { templateId: this.orderStatusChangedSmsTemplateId, parameters: { @@ -104,8 +119,8 @@ export class OrderListeners { }, }, pushNotif: { - title: `Order #${event.orderNumber} status is changed to ${event.newStatus} .`, - content: `Order #${event.orderNumber} status is changed to ${event.newStatus} .`, + title: `تغییر وضعیت سفارش`, + content: `وضعیت سفارش شماره ${event.orderNumber} به ${this.getStatusFarsi(event.newStatus)} تغییر کرد`, icon: `/`, action: { type: NotifTitleEnum.ORDER_STATUS_CHANGED, @@ -126,140 +141,140 @@ export class OrderListeners { } } - private factory(orderStatus: OrderStatus, event: OrderStatusChangedEvent) { - switch (orderStatus) { - case OrderStatus.CONFIRMED: - return { - message: { - title: NotifTitleEnum.ORDER_STATUS_CHANGED, - content: `Order ${event.orderNumber} confirmed .`, - sms: { - templateId: this.orderCreatedSmsTemplateId, - parameters: { - orderNumber: event.orderNumber, - }, - }, - pushNotif: { - title: `Order ${event.orderNumber} has been confirmed successfully`, - content: `Order ${event.orderNumber} has been confirmed successfully`, - icon: `Order ${event.orderNumber} has been confirmed successfully`, - action: { - type: NotifTitleEnum.ORDER_STATUS_CHANGED, - url: ``, - }, - }, - }, - }; - case OrderStatus.PREPARING: - return { - message: { - title: NotifTitleEnum.ORDER_STATUS_CHANGED, - content: `Order ${event.orderNumber} is preparing.`, - sms: { - templateId: this.orderCreatedSmsTemplateId, - parameters: { - orderNumber: event.orderNumber, - }, - }, - pushNotif: { - title: `Order ${event.orderNumber} is preparing`, - content: `Order ${event.orderNumber} is preparing`, - icon: `Order ${event.orderNumber} is preparing`, - action: { - type: NotifTitleEnum.ORDER_STATUS_CHANGED, - url: ``, - }, - }, - }, - }; - case OrderStatus.DELIVERED_TO_RECEPTIONIST: - return { - message: { - title: NotifTitleEnum.ORDER_STATUS_CHANGED, - content: `Order ${event.orderNumber} is ready.`, - sms: { - templateId: this.orderCreatedSmsTemplateId, - parameters: { - orderNumber: event.orderNumber, - }, - }, - pushNotif: { - title: `Order ${event.orderNumber} is ready`, - content: `Order ${event.orderNumber} is ready`, - icon: `Order ${event.orderNumber} is ready`, - action: { - type: NotifTitleEnum.ORDER_STATUS_CHANGED, - url: ``, - }, - }, - }, - }; - case OrderStatus.SHIPPED: - return { - message: { - title: NotifTitleEnum.ORDER_STATUS_CHANGED, - content: `Order ${event.orderNumber} is shipped.`, - sms: { - templateId: this.orderCreatedSmsTemplateId, - parameters: { - orderNumber: event.orderNumber, - }, - }, - pushNotif: { - title: `Order ${event.orderNumber} is shipped`, - content: `Order ${event.orderNumber} is shipped`, - icon: `Order ${event.orderNumber} is shipped`, - action: { - type: NotifTitleEnum.ORDER_STATUS_CHANGED, - url: ``, - }, - }, - }, - }; - case OrderStatus.CANCELED: - return { - message: { - title: NotifTitleEnum.ORDER_STATUS_CHANGED, - content: `Order ${event.orderNumber} is canceled.`, - sms: { - templateId: this.orderCreatedSmsTemplateId, - parameters: { - orderNumber: event.orderNumber, - }, - }, - pushNotif: { - title: `Order ${event.orderNumber} is canceled`, - content: `Order ${event.orderNumber} is canceled`, - icon: `Order ${event.orderNumber} is canceled`, - action: { - type: NotifTitleEnum.ORDER_STATUS_CHANGED, - url: ``, - }, - }, - }, - }; - default: - return { - message: { - title: NotifTitleEnum.ORDER_STATUS_CHANGED, - content: `Order ${event.orderNumber} is ....`, - sms: { - templateId: this.orderCreatedSmsTemplateId, - parameters: { - orderNumber: event.orderNumber, - }, - }, - pushNotif: { - title: `Order ${event.orderNumber} is ...`, - content: `Order ${event.orderNumber} is ...`, - icon: `Order ${event.orderNumber} is ...`, - action: { - type: NotifTitleEnum.ORDER_STATUS_CHANGED, - url: ``, - }, - }, - }, - }; - } - } + // private factory(orderStatus: OrderStatus, event: OrderStatusChangedEvent) { + // switch (orderStatus) { + // case OrderStatus.CONFIRMED: + // return { + // message: { + // title: NotifTitleEnum.ORDER_STATUS_CHANGED, + // content: `Order ${event.orderNumber} confirmed .`, + // sms: { + // templateId: this.orderCreatedSmsTemplateId, + // parameters: { + // orderNumber: event.orderNumber, + // }, + // }, + // pushNotif: { + // title: `تایید سفارش`, + // content: `سفارش شماره ${event.orderNumber} با موفقیت تایید شد`, + // icon: `Order ${event.orderNumber} has been confirmed successfully`, + // action: { + // type: NotifTitleEnum.ORDER_STATUS_CHANGED, + // url: ``, + // }, + // }, + // }, + // }; + // case OrderStatus.PREPARING: + // return { + // message: { + // title: NotifTitleEnum.ORDER_STATUS_CHANGED, + // content: `سفارش شماره ${event.orderNumber} در حال آماده‌سازی است`, + // sms: { + // templateId: this.orderCreatedSmsTemplateId, + // parameters: { + // orderNumber: event.orderNumber, + // }, + // }, + // pushNotif: { + // title: `آماده‌سازی سفارش`, + // content: `سفارش شماره ${event.orderNumber} در حال آماده‌سازی است`, + // icon: `Order ${event.orderNumber} is preparing`, + // action: { + // type: NotifTitleEnum.ORDER_STATUS_CHANGED, + // url: ``, + // }, + // }, + // }, + // }; + // case OrderStatus.DELIVERED_TO_RECEPTIONIST: + // return { + // message: { + // title: NotifTitleEnum.ORDER_STATUS_CHANGED, + // content: `سفارش شماره ${event.orderNumber} آماده است`, + // sms: { + // templateId: this.orderCreatedSmsTemplateId, + // parameters: { + // orderNumber: event.orderNumber, + // }, + // }, + // pushNotif: { + // title: `سفارش آماده است`, + // content: `سفارش شماره ${event.orderNumber} آماده است`, + // icon: `Order ${event.orderNumber} is ready`, + // action: { + // type: NotifTitleEnum.ORDER_STATUS_CHANGED, + // url: ``, + // }, + // }, + // }, + // }; + // case OrderStatus.SHIPPED: + // return { + // message: { + // title: NotifTitleEnum.ORDER_STATUS_CHANGED, + // content: `سفارش شماره ${event.orderNumber} ارسال شد`, + // sms: { + // templateId: this.orderCreatedSmsTemplateId, + // parameters: { + // orderNumber: event.orderNumber, + // }, + // }, + // pushNotif: { + // title: `ارسال سفارش`, + // content: `سفارش شماره ${event.orderNumber} ارسال شد`, + // icon: `Order ${event.orderNumber} is shipped`, + // action: { + // type: NotifTitleEnum.ORDER_STATUS_CHANGED, + // url: ``, + // }, + // }, + // }, + // }; + // case OrderStatus.CANCELED: + // return { + // message: { + // title: NotifTitleEnum.ORDER_STATUS_CHANGED, + // content: `سفارش شماره ${event.orderNumber} لغو شد`, + // sms: { + // templateId: this.orderCreatedSmsTemplateId, + // parameters: { + // orderNumber: event.orderNumber, + // }, + // }, + // pushNotif: { + // title: `لغو سفارش`, + // content: `سفارش شماره ${event.orderNumber} لغو شد`, + // icon: `Order ${event.orderNumber} is canceled`, + // action: { + // type: NotifTitleEnum.ORDER_STATUS_CHANGED, + // url: ``, + // }, + // }, + // }, + // }; + // default: + // return { + // message: { + // title: NotifTitleEnum.ORDER_STATUS_CHANGED, + // content: `Order ${event.orderNumber} is ....`, + // sms: { + // templateId: this.orderCreatedSmsTemplateId, + // parameters: { + // orderNumber: event.orderNumber, + // }, + // }, + // pushNotif: { + // title: `Order ${event.orderNumber} is ...`, + // content: `Order ${event.orderNumber} is ...`, + // icon: `Order ${event.orderNumber} is ...`, + // action: { + // type: NotifTitleEnum.ORDER_STATUS_CHANGED, + // url: ``, + // }, + // }, + // }, + // }; + // } + // } } diff --git a/src/modules/orders/providers/orders.service.ts b/src/modules/orders/providers/orders.service.ts index e7e4351..a5bc9a6 100644 --- a/src/modules/orders/providers/orders.service.ts +++ b/src/modules/orders/providers/orders.service.ts @@ -22,6 +22,7 @@ import { BulkReserveFoodDto } from 'src/modules/inventory/dto/bulk-reserve-food. import { StatusTransitionRef } from '../interface/order.interface'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events'; +import { OrderMessage } from 'src/common/enums/message.enum'; type OrderItemData = { food: Food; quantity: number; unitPrice: number; discount: number }; type ValidatedCartForOrder = { @@ -224,7 +225,7 @@ export class OrdersService { }, ); if (!order) { - throw new NotFoundException('Order not found'); + throw new NotFoundException(OrderMessage.NOT_FOUND); } return order; } @@ -291,11 +292,11 @@ export class OrdersService { private assertStatusTransitionAllowed(order: Order, to: OrderStatus, ref: StatusTransitionRef) { const paymentMethod = order.paymentMethod?.method; if (!paymentMethod) { - throw new BadRequestException('Order payment method is missing'); + throw new BadRequestException(OrderMessage.PAYMENT_METHOD_MISSING); } if (!this.canTransition(order.status, to, paymentMethod, ref)) { - throw new BadRequestException(`Invalid status transition: ${order.status} -> ${to}`); + throw new BadRequestException(OrderMessage.INVALID_STATUS_TRANSITION); } } @@ -336,70 +337,66 @@ export class OrdersService { { id: orderId, restaurant: { id: restId } }, { populate: ['paymentMethod'] }, ); - if (!order) throw new NotFoundException('Order not found'); + if (!order) throw new NotFoundException(OrderMessage.NOT_FOUND); return order; } private assertCartHasItems(cart: Cart) { if (!cart.items || cart.items.length === 0) { - throw new BadRequestException('Cart is empty. Add items to cart before creating an order.'); + throw new BadRequestException(OrderMessage.CART_EMPTY); } } private assertCartHasDeliveryMethod(cart: Cart) { if (!cart.deliveryMethodId) { - throw new NotFoundException('Delivery method not found'); + throw new NotFoundException(OrderMessage.DELIVERY_METHOD_NOT_FOUND); } } private assertCartHasPaymentMethod(cart: Cart) { if (!cart.paymentMethodId) { - throw new BadRequestException( - 'Payment method is required. Please set a payment method before creating an order.', - ); + throw new BadRequestException(OrderMessage.PAYMENT_METHOD_REQUIRED); } } private async getUserOrFail(userId: string): Promise { const user = await this.em.findOne(User, { id: userId }); - if (!user) throw new NotFoundException('User not found'); + if (!user) throw new NotFoundException(OrderMessage.USER_NOT_FOUND); return user; } private async getRestaurantOrFail(restaurantId: string): Promise { const restaurant = await this.em.findOne(Restaurant, { id: restaurantId }); - if (!restaurant) throw new NotFoundException('Restaurant not found'); + if (!restaurant) throw new NotFoundException(OrderMessage.RESTAURANT_NOT_FOUND); return restaurant; } private async getDeliveryOrFail(deliveryId: string): Promise { const delivery = await this.em.findOne(Delivery, { id: deliveryId }); - if (!delivery) throw new NotFoundException('Delivery not found'); + if (!delivery) throw new NotFoundException(OrderMessage.DELIVERY_NOT_FOUND); return delivery; } private assertMeetsMinOrderForDelivery(cart: Cart, delivery: Delivery) { const minOrderPrice = Number(delivery.minOrderPrice) || 0; if (minOrderPrice > 0 && cart.total < minOrderPrice) { - throw new BadRequestException( - `Minimum order amount for this delivery method is ${minOrderPrice}. Current total is ${cart.total}.`, - ); + throw new BadRequestException(OrderMessage.MIN_ORDER_AMOUNT_NOT_MET); } } private assertDeliveryMethodRequirements(cart: Cart, delivery: Delivery) { if (delivery.method === DeliveryMethodEnum.DineIn) { if (!cart.tableNumber || cart.tableNumber.trim() === '') { - throw new BadRequestException('Table number is required when delivery method is DineIn'); + throw new BadRequestException(OrderMessage.TABLE_NUMBER_REQUIRED); } } if (delivery.method === DeliveryMethodEnum.DeliveryCourier && !cart.userAddress) { - throw new BadRequestException('Address is required. Please set a delivery address before creating an order.'); + throw new BadRequestException(OrderMessage.ADDRESS_REQUIRED); } if (delivery.method === DeliveryMethodEnum.DeliveryCar && !cart.carAddress) { - throw new BadRequestException('Car address is required. Please set a car address before creating an order.'); + throw new BadRequestException(OrderMessage.CAR_ADDRESS_REQUIRED); } } @@ -422,7 +419,7 @@ export class OrdersService { private assertPaymentMethodEnabled(paymentMethod: PaymentMethod) { if (!paymentMethod.enabled) { - throw new BadRequestException('Payment method is not enabled for this restaurant'); + throw new BadRequestException(OrderMessage.PAYMENT_METHOD_NOT_ENABLED); } } @@ -431,10 +428,10 @@ export class OrdersService { for (const cartItem of cart.items) { const food = await this.em.findOne(Food, { id: cartItem.foodId }, { populate: ['restaurant', 'inventory'] }); - if (!food) throw new NotFoundException(`Food with ID ${cartItem.foodId} not found`); + if (!food) throw new NotFoundException(OrderMessage.FOOD_NOT_FOUND); if (food.restaurant.id !== restaurantId) { - throw new BadRequestException(`Food ${food.title || food.id} does not belong to restaurant ${restaurantId}`); + throw new BadRequestException(OrderMessage.FOOD_NOT_BELONGS_TO_RESTAURANT); } this.assertFoodHasSufficientStock(food, cartItem.quantity); @@ -453,9 +450,7 @@ export class OrdersService { private assertFoodHasSufficientStock(food: Food, quantity: number) { const availableStock = food.inventory?.availableStock ?? 0; if (availableStock < quantity) { - throw new BadRequestException( - `Insufficient stock for food ${food.title || food.id}. Available: ${availableStock}, Requested: ${quantity}`, - ); + throw new BadRequestException(OrderMessage.FOOD_NOT_FOUND); } } diff --git a/src/modules/pager/controllers/pager.controller.ts b/src/modules/pager/controllers/pager.controller.ts index 775da14..6d2c7c9 100644 --- a/src/modules/pager/controllers/pager.controller.ts +++ b/src/modules/pager/controllers/pager.controller.ts @@ -10,6 +10,7 @@ import type { FastifyReply, FastifyRequest } from 'fastify'; import { AdminAuthGuard } from '../../auth/guards/adminAuth.guard'; import { AdminId } from 'src/common/decorators/admin-id.decorator'; import { UpdatePagerStatusDto } from '../dto/update-pager.dto'; +import { PagerMessage } from 'src/common/enums/message.enum'; @ApiTags('pager') @Controller() @@ -49,7 +50,7 @@ export class PagerController { }); return reply.code(200).send({ success: true, - message: 'Pager request created successfully', + message: PagerMessage.CREATED_SUCCESS, data: null, }); } diff --git a/src/modules/payments/gateways/zarinpal.gateway.ts b/src/modules/payments/gateways/zarinpal.gateway.ts index 37beae7..1c14fa5 100755 --- a/src/modules/payments/gateways/zarinpal.gateway.ts +++ b/src/modules/payments/gateways/zarinpal.gateway.ts @@ -12,6 +12,7 @@ import { IZarinpalVerifyResponse, } from '../interface/gateway'; import { ConfigService } from '@nestjs/config'; +import { PaymentMessage } from 'src/common/enums/message.enum'; @Injectable() export class ZarinpalGateway implements IPaymentGateway { @@ -64,7 +65,7 @@ export class ZarinpalGateway implements IPaymentGateway { if (!data) { this.logger.error('Invalid response from Zarinpal API (missing data)', JSON.stringify(res.data)); - throw new BadRequestException('Invalid response from Zarinpal API'); + throw new BadRequestException(PaymentMessage.ZARINPAL_INVALID_RESPONSE); } if ((Array.isArray(errors) && errors.length > 0) || code !== 100 || !authority) { @@ -79,7 +80,7 @@ export class ZarinpalGateway implements IPaymentGateway { orderId, }), ); - throw new BadRequestException(message ?? 'Zarinpal payment request error'); + throw new BadRequestException(message ?? PaymentMessage.ZARINPAL_PAYMENT_REQUEST_ERROR); } return { transactionId: authority }; @@ -98,12 +99,12 @@ export class ZarinpalGateway implements IPaymentGateway { orderId, }), ); - throw new BadRequestException('Zarinpal payment request error'); + throw new BadRequestException(PaymentMessage.ZARINPAL_PAYMENT_REQUEST_ERROR); } const errorMessage = error instanceof Error ? error.message : 'Unknown error'; this.logger.error('Zarinpal payment request error', errorMessage); - throw new BadRequestException(`Failed to request payment from gateway: ${errorMessage}`); + throw new BadRequestException(PaymentMessage.GATEWAY_ERROR); } } @@ -124,14 +125,14 @@ export class ZarinpalGateway implements IPaymentGateway { // Check if response data exists if (!res.data || !res.data.data) { - throw new BadRequestException('Invalid response from Zarinpal API'); + throw new BadRequestException(PaymentMessage.ZARINPAL_INVALID_RESPONSE); } const { code, message, ref_id, card_pan } = res.data.data; // Check if there are errors in the response if (code !== 100 && code !== 0) { - throw new BadRequestException(message ?? 'Zarinpal error'); + throw new BadRequestException(message ?? PaymentMessage.ZARINPAL_VERIFY_ERROR); } return { @@ -146,7 +147,7 @@ export class ZarinpalGateway implements IPaymentGateway { throw new BadRequestException(error.response.data); } const errorMessage = error instanceof Error ? error.message : 'Unknown error'; - throw new BadRequestException(`Failed to verify payment with gateway: ${errorMessage}`); + throw new BadRequestException(PaymentMessage.GATEWAY_ERROR); } } diff --git a/src/modules/payments/listeners/payment.listeners.ts b/src/modules/payments/listeners/payment.listeners.ts index 322cfcf..2ffa29e 100644 --- a/src/modules/payments/listeners/payment.listeners.ts +++ b/src/modules/payments/listeners/payment.listeners.ts @@ -20,6 +20,15 @@ export class PaymentListeners { this.paymentSuccessSmsTemplateId = this.configService.get('SMS_PATTERN_PAYMENT_SUCCESS') ?? '123'; } + private getPaymentMethodFarsi(method: string): string { + const methodMap: Record = { + Cash: 'نقدی', + Wallet: 'کیف پول', + Online: 'آنلاین', + }; + return methodMap[method] || method; + } + @OnEvent(paymentSucceedEvent.name) async handlePaymentSucceed(event: paymentSucceedEvent) { try { @@ -36,7 +45,7 @@ export class PaymentListeners { restaurantId: event.restaurantId, message: { title: NotifTitleEnum.PAYMENT_SUCCESS, - content: `payment order #${event.orderNumber} has been paid successfully with ${event.paymentMethod} method and total amount of ${event.total}`, + content: `پرداخت سفارش شماره ${event.orderNumber} با روش ${this.getPaymentMethodFarsi(event.paymentMethod)} و مبلغ ${event.total} تومان با موفقیت انجام شد`, sms: { templateId: this.paymentSuccessSmsTemplateId, parameters: { @@ -45,8 +54,8 @@ export class PaymentListeners { }, }, pushNotif: { - title: `Payment Order ${event.orderNumber} has been paid successfully with ${event.paymentMethod} method and total amount of ${event.total} `, - content: `Payment Order ${event.orderNumber} has been paid successfully with ${event.paymentMethod} method and total amount of ${event.total} `, + title: `پرداخت موفق`, + content: `پرداخت سفارش شماره ${event.orderNumber} با روش ${this.getPaymentMethodFarsi(event.paymentMethod)} و مبلغ ${event.total} تومان با موفقیت انجام شد`, icon: ``, action: { type: NotifTitleEnum.PAYMENT_SUCCESS, diff --git a/src/modules/payments/services/payment-method.service.ts b/src/modules/payments/services/payment-method.service.ts index 2a9b30c..cb40dcf 100644 --- a/src/modules/payments/services/payment-method.service.ts +++ b/src/modules/payments/services/payment-method.service.ts @@ -6,6 +6,7 @@ import { CreatePaymentMethodDto } from '../dto/create-payment-method.dto'; import { UpdatePaymentMethodDto } from '../dto/update-payment-method.dto'; import { RequiredEntityData } from '@mikro-orm/core'; import { Restaurant } from '../../restaurants/entities/restaurant.entity'; +import { RestMessage, PaymentMessage } from 'src/common/enums/message.enum'; @Injectable() export class PaymentMethodService { @@ -18,7 +19,7 @@ export class PaymentMethodService { // Check if restaurant exists const restaurant = await this.em.findOne(Restaurant, { id: restId }); if (!restaurant) { - throw new NotFoundException(`Restaurant with ID ${restId} not found`); + throw new NotFoundException(RestMessage.NOT_FOUND); } const paymentMethod = this.paymentMethodRepository.create({ @@ -36,7 +37,7 @@ export class PaymentMethodService { async findOne(id: string): Promise { const paymentMethod = await this.paymentMethodRepository.findOne({ id }, { populate: ['restaurant'] }); if (!paymentMethod) { - throw new NotFoundException(`PaymentMethod with ID ${id} not found`); + throw new NotFoundException(PaymentMessage.PAYMENT_METHOD_NOT_FOUND); } return paymentMethod; } diff --git a/src/modules/payments/services/payments.service.ts b/src/modules/payments/services/payments.service.ts index 0e505ff..0d9af49 100644 --- a/src/modules/payments/services/payments.service.ts +++ b/src/modules/payments/services/payments.service.ts @@ -9,6 +9,7 @@ import { UserWallet } from 'src/modules/users/entities/user-wallet.entity'; import { OrderPaymentContext } from '../interface/payment'; import { OrderStatus } from 'src/modules/orders/interface/order.interface'; import { ChartPeriodEnum, PaymentChartDto } from '../dto/payment-chart.dto'; +import { PaymentMessage, OrderMessage } from 'src/common/enums/message.enum'; @Injectable() export class PaymentsService { @@ -40,7 +41,7 @@ export class PaymentsService { return this.handleOnlinePayment(ctx); default: - throw new BadRequestException('Unsupported payment method'); + throw new BadRequestException(PaymentMessage.UNSUPPORTED_PAYMENT_METHOD); } } @@ -52,22 +53,22 @@ export class PaymentsService { ); if (!order) { - throw new NotFoundException('Order not found'); + throw new NotFoundException(OrderMessage.NOT_FOUND); } if (order.total <= 0) { - throw new BadRequestException('Amount must be greater than zero'); + throw new BadRequestException(PaymentMessage.AMOUNT_MUST_BE_GREATER_THAN_ZERO); } const pm = order.paymentMethod; if (!pm) { - throw new NotFoundException('Payment method not found'); + throw new NotFoundException(PaymentMessage.PAYMENT_METHOD_NOT_FOUND); } if (pm.method === PaymentMethodEnum.Online) { - if (!pm.gateway) throw new BadRequestException('Gateway is required for online payment'); - if (!pm.merchantId) throw new BadRequestException('Merchant ID is required for online payment'); - if (!pm.restaurant?.domain) throw new BadRequestException('Restaurant domain is required for online payment'); + if (!pm.gateway) throw new BadRequestException(PaymentMessage.GATEWAY_REQUIRED); + if (!pm.merchantId) throw new BadRequestException(PaymentMessage.MERCHANT_ID_REQUIRED); + if (!pm.restaurant?.domain) throw new BadRequestException(PaymentMessage.RESTAURANT_DOMAIN_REQUIRED); } return { @@ -91,7 +92,7 @@ export class PaymentsService { private async handleWalletPayment(ctx: OrderPaymentContext): Promise { await this.em.transactional(async em => { const order = await em.findOne(Order, { id: ctx.order.id }, { populate: ['user', 'restaurant'] }); - if (!order) throw new NotFoundException('Order not found'); + if (!order) throw new NotFoundException(OrderMessage.NOT_FOUND); if (order.status === OrderStatus.PAID) { return; @@ -169,7 +170,7 @@ export class PaymentsService { ); if (!payment) { - throw new NotFoundException('Payment not found'); + throw new NotFoundException(PaymentMessage.PAYMENT_NOT_FOUND); } if (payment.status === PaymentStatusEnum.Paid) { @@ -178,7 +179,7 @@ export class PaymentsService { const pm = payment.order.paymentMethod; if (!pm?.merchantId || !payment.gateway) { - throw new BadRequestException('Invalid payment configuration'); + throw new BadRequestException(PaymentMessage.INVALID_PAYMENT_CONFIGURATION); } const gateway = this.gatewayManager.get(payment.gateway); @@ -215,13 +216,13 @@ export class PaymentsService { const payment = await this.em.transactional(async em => { const payment = await em.findOne(Payment, id, { populate: ['order'] }); if (!payment) { - throw new NotFoundException('Payment not found'); + throw new NotFoundException(PaymentMessage.PAYMENT_NOT_FOUND); } if (payment.method !== PaymentMethodEnum.Cash) { - throw new BadRequestException('Payment method is not cash'); + throw new BadRequestException(PaymentMessage.PAYMENT_METHOD_NOT_CASH); } if (payment.status === PaymentStatusEnum.Paid) { - throw new BadRequestException('Payment already paid'); + throw new BadRequestException(PaymentMessage.PAYMENT_ALREADY_PAID); } payment.order.status = OrderStatus.PAID; payment.status = PaymentStatusEnum.Paid; @@ -269,7 +270,7 @@ export class PaymentsService { if (existing) { if (existing.method !== params.method) { - throw new BadRequestException('Existing pending payment method does not match order payment method'); + throw new BadRequestException(PaymentMessage.EXISTING_PENDING_PAYMENT_MISMATCH); } return existing; diff --git a/src/modules/users/controllers/users.controller.ts b/src/modules/users/controllers/users.controller.ts index 2fd191e..57c0d7f 100644 --- a/src/modules/users/controllers/users.controller.ts +++ b/src/modules/users/controllers/users.controller.ts @@ -10,6 +10,7 @@ import { RestId } from 'src/common/decorators'; import { FindUsersDto } from '../dto/find-user.dto'; import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard'; import { API_HEADER_SLUG } from 'src/common/constants/index'; +import { UserSuccessMessage } from 'src/common/enums/message.enum'; @ApiTags('User') @Controller() @@ -107,7 +108,7 @@ export class UsersController { @Delete('public/user/addresses/:addressId') async deleteUserAddress(@UserId() userId: string, @Param('addressId') addressId: string) { await this.userService.deleteUserAddress(userId, addressId); - return { message: 'Address deleted successfully' }; + return { message: UserSuccessMessage.ADDRESS_DELETED_SUCCESS }; } @UseGuards(AuthGuard) @@ -129,7 +130,7 @@ export class UsersController { async convertScoreToWallet(@UserId() userId: string, @RestId() restId: string) { await this.userService.convertScoreToWallet(userId, restId); return { - message: 'Score converted to wallet successfully', + message: UserSuccessMessage.SCORE_CONVERTED_SUCCESS, }; }