diff --git a/src/modules/foods/controllers/food.controller.ts b/src/modules/foods/controllers/food.controller.ts index 3300d35..a945e0c 100644 --- a/src/modules/foods/controllers/food.controller.ts +++ b/src/modules/foods/controllers/food.controller.ts @@ -117,6 +117,16 @@ export class FoodController { return this.foodsService.findAdminById(restId, id); } + @UseGuards(AdminAuthGuard) + @ApiBearerAuth() + @Permissions(Permission.MANAGE_FOODS) + @Post('admin/foods/:id/clone') + @ApiOperation({ summary: 'Clone a food' }) + @ApiParam({ name: 'id', required: true, description: 'Food ID to clone' }) + clone(@Param('id') id: string, @RestId() restId: string) { + return this.foodsService.clone(restId, id); + } + @UseGuards(AdminAuthGuard) @ApiBearerAuth() @Permissions(Permission.MANAGE_FOODS) diff --git a/src/modules/foods/providers/food.service.ts b/src/modules/foods/providers/food.service.ts index 938fe7a..d9210de 100644 --- a/src/modules/foods/providers/food.service.ts +++ b/src/modules/foods/providers/food.service.ts @@ -365,6 +365,57 @@ export class FoodService { return savedFood ?? food; } + async clone(restId: string, id: string) { + const source = await this.foodRepository.findOne( + { id, restaurant: { id: restId } }, + { populate: ['category', 'restaurant', 'inventory'] }, + ); + if (!source) { + throw new NotFoundException(FoodMessage.NOT_FOUND); + } + + const { food, inventory } = await this.em.transactional(async em => { + const data: RequiredEntityData = { + title: `کپی ${source.title}`, + desc: source.desc, + content: source.content, + price: source.price, + order: source.order, + prepareTime: source.prepareTime, + weekDays: source.weekDays, + mealTypes: source.mealTypes, + isActive: source.isActive, + images: source.images, + inPlaceServe: source.inPlaceServe, + pickupServe: source.pickupServe, + discount: source.discount, + isSpecialOffer: source.isSpecialOffer, + score: null, + restaurant: source.restaurant, + category: source.category, + }; + + const food = em.create(Food, data); + const newInventoryRecord = em.create(Inventory, { + food, + availableStock: source.inventory?.availableStock ?? 0, + totalStock: source.inventory?.totalStock ?? 0, + }); + + await em.flush(); + return { food, inventory: newInventoryRecord }; + }); + + const savedFood = food?.id + ? await this.foodRepository.findOne({ id: food.id }, { populate: ['category', 'restaurant', 'inventory'] }) + : null; + const savedInventory = inventory?.id ? await this.em.findOne(Inventory, { id: inventory.id }) : inventory; + + await this.invalidateRestaurantFoodsCache(source.restaurant.slug); + + return { food: savedFood ?? food, inventory: savedInventory ?? inventory }; + } + async remove(restId: string, id: string): Promise { const food = await this.foodRepository.findOne({ id, restaurant: { id: restId } }, { populate: ['restaurant'] }); if (!food) {