farsi messages

This commit is contained in:
2025-12-22 19:12:03 +03:30
parent ed251611c4
commit 1802b05e74
14 changed files with 365 additions and 230 deletions
+108
View File
@@ -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 = 'تماس با موفقیت حذف شد',
}
@@ -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<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);
}
const existingItem = cart.items[itemIndex];
@@ -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<Food> {
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<User> {
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<UserAddress> {
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<Food> {
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<Restaurant> {
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);
}
}
+7 -6
View File
@@ -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<Cart> {
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
@@ -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<Delivery> {
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);
@@ -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)
+157 -142
View File
@@ -24,6 +24,21 @@ export class OrderListeners {
this.orderStatusChangedSmsTemplateId = this.configService.get<string>('SMS_PATTERN_ORDER_STATUS_CHANGE') ?? '123';
}
private getStatusFarsi(status: OrderStatus): string {
const statusMap: Record<OrderStatus, string> = {
[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: ``,
// },
// },
// },
// };
// }
// }
}
+19 -24
View File
@@ -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<User> {
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<Restaurant> {
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<Delivery> {
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);
}
}
@@ -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,
});
}
@@ -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);
}
}
@@ -20,6 +20,15 @@ export class PaymentListeners {
this.paymentSuccessSmsTemplateId = this.configService.get<string>('SMS_PATTERN_PAYMENT_SUCCESS') ?? '123';
}
private getPaymentMethodFarsi(method: string): string {
const methodMap: Record<string, string> = {
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,
@@ -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<PaymentMethod> {
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;
}
@@ -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<void> {
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;
@@ -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,
};
}