This commit is contained in:
2026-03-09 11:38:43 +03:30
commit 5fda2d6d8c
339 changed files with 186841 additions and 0 deletions
@@ -0,0 +1,77 @@
import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { EntityManager } from '@mikro-orm/postgresql';
import { FoodRepository } from '../../foods/repositories/food.repository';
import { ReviewRepository } from '../repositories/review.repository';
import { ReviewStatus } from '../enums/review-status.enum';
@Injectable()
export class FoodRatingCronService {
private readonly logger = new Logger(FoodRatingCronService.name);
constructor(
private readonly em: EntityManager,
private readonly foodRepository: FoodRepository,
private readonly reviewRepository: ReviewRepository,
) { }
/**
* Cron job that runs at midnight every day (00:00:00 UTC)
* Calculates and updates the average rating for each restaurant food
*/
@Cron('0 0 * * *', {
name: 'calculateFoodRatings',
timeZone: 'UTC',
})
async handleCron() {
this.logger.log('Starting daily food rating calculation cron job...');
try {
// Get all foods from all restaurants
const foods = await this.foodRepository.find({});
this.logger.log(`Found ${foods.length} foods to process`);
let updatedCount = 0;
let errorCount = 0;
// Process each food item
for (const food of foods) {
try {
// Get all approved reviews for this food that are not deleted
const reviews = await this.reviewRepository.find(
{
food: { id: food.id },
status: ReviewStatus.APPROVED,
deletedAt: null,
},
{ fields: ['rating'] },
);
// Calculate average rating
let averageRating = 0;
if (reviews.length > 0) {
const sum = reviews.reduce((acc, review) => acc + review.rating, 0);
averageRating = sum / reviews.length;
}
// Update food score
food.score = parseFloat(averageRating.toFixed(2));
this.em.persist(food);
updatedCount++;
} catch (error) {
this.logger.error(`Error processing food ${food.id}: ${error.message}`, error.stack);
errorCount++;
}
}
// Flush all updates at once for better performance
await this.em.flush();
this.logger.log(`Food rating calculation completed. Updated: ${updatedCount}, Errors: ${errorCount}`);
} catch (error) {
this.logger.error(`Error in food rating cron job: ${error.message}`, error.stack);
}
}
}