UNPKG

@devx-commerce/plugin-product-reviews

Version:
139 lines 11.5 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("@medusajs/framework/utils"); const models_1 = require("./models"); const DEFAULT_CONFIGS = [ { key: "AUTO_PUBLISH", value: false }, { key: "VERIFIED_PURCHASES_ONLY", value: false }, ]; class ProductReviewService extends (0, utils_1.MedusaService)({ ProductReview: models_1.ProductReviewModel, ProductReviewResponse: models_1.ProductReviewResponseModel, ProductReviewStats: models_1.ProductReviewStatsModel, ReviewAssociatedMedia: models_1.ReviewAssociatedMediaModel, ProductReviewConfig: models_1.ProductReviewConfigModel, }) { constructor(container) { super(container); this.ensureDefaultConfigs(); } async ensureDefaultConfigs() { const existingConfigs = await this.listProductReviewConfigs(); for (const defaultConfig of DEFAULT_CONFIGS) { const configExists = existingConfigs.some((config) => config.key === defaultConfig.key); if (!configExists) { await this.createProductReviewConfigs(defaultConfig); } } } async refreshProductReviewStats(productIds, sharedContext) { const calculatedStats = await this.calculateProductReviewStats(productIds, sharedContext); const foundStats = await this.listProductReviewStats({ product_id: productIds }, {}); // Group existing stats by product_id to handle duplicates const statsByProduct = foundStats.reduce((acc, stat) => { if (!acc[stat.product_id]) { acc[stat.product_id] = []; } acc[stat.product_id].push(stat); return acc; }, {}); const updatedStats = await Promise.all(calculatedStats.map(async (calculatedStat) => { const existingStats = statsByProduct[calculatedStat.product_id] || []; // If there are multiple existing stats, set all of them to 0 first if (existingStats.length > 1) { await Promise.all(existingStats.map((stat) => this.updateProductReviewStats({ id: stat.id, product_id: stat.product_id, review_count: 0, average_rating: 0, rating_count_1: 0, rating_count_2: 0, rating_count_3: 0, rating_count_4: 0, rating_count_5: 0, }))); } if (existingStats.length > 0) { // Use the first existing stat (or the only one after setting others to 0) const foundStat = existingStats[0]; return await this.updateProductReviewStats({ id: foundStat.id, ...calculatedStat, }); } return await this.createProductReviewStats(calculatedStat); })); // Handle products that have existing stats but no calculated stats (should be set to 0) const calculatedProductIds = new Set(calculatedStats.map((stat) => stat.product_id)); const productsToDelete = Object.keys(statsByProduct).filter((productId) => !calculatedProductIds.has(productId)); if (productsToDelete.length > 0) { for (const productId of productsToDelete) { const existingStats = statsByProduct[productId]; await Promise.all(existingStats.map((stat) => this.updateProductReviewStats({ id: stat.id, product_id: stat.product_id, review_count: 0, average_rating: 0, rating_count_1: 0, rating_count_2: 0, rating_count_3: 0, rating_count_4: 0, rating_count_5: 0, }))); } } return updatedStats; } async calculateProductReviewStats(productIds, sharedContext) { let whereClause = ` pr.is_admin_verified = true AND pr.deleted_at IS NULL `; if (productIds.length > 0) { const ids = productIds.map((id) => `'${id}'`).join(", "); whereClause = ` pr.product_id IN (${ids}) AND ${whereClause} `; } const SQL = ` SELECT pr.product_id, COUNT(*) AS review_count, CAST(AVG(pr.rating) AS DECIMAL(10, 2)) AS average_rating, SUM(CASE WHEN pr.rating = 1 THEN 1 ELSE 0 END) AS rating_count_1, SUM(CASE WHEN pr.rating = 2 THEN 1 ELSE 0 END) AS rating_count_2, SUM(CASE WHEN pr.rating = 3 THEN 1 ELSE 0 END) AS rating_count_3, SUM(CASE WHEN pr.rating = 4 THEN 1 ELSE 0 END) AS rating_count_4, SUM(CASE WHEN pr.rating = 5 THEN 1 ELSE 0 END) AS rating_count_5 FROM product_review pr WHERE ${whereClause} GROUP BY pr.product_id`; const productReviewStats = await sharedContext.manager.execute(SQL); return productReviewStats.map((s) => ({ ...s, average_rating: parseFloat(s.average_rating), })); } } __decorate([ (0, utils_1.InjectManager)(), __param(1, (0, utils_1.MedusaContext)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Array, Object]), __metadata("design:returntype", Promise) ], ProductReviewService.prototype, "calculateProductReviewStats", null); exports.default = ProductReviewService; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL3Byb2R1Y3QtcmV2aWV3L3NlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7QUFDQSxxREFJbUM7QUFHbkMscUNBTWtCO0FBY2xCLE1BQU0sZUFBZSxHQUFHO0lBQ3RCLEVBQUUsR0FBRyxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFO0lBQ3JDLEVBQUUsR0FBRyxFQUFFLHlCQUF5QixFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUU7Q0FDakQsQ0FBQztBQUVGLE1BQU0sb0JBQXFCLFNBQVEsSUFBQSxxQkFBYSxFQUFDO0lBQy9DLGFBQWEsRUFBRSwyQkFBa0I7SUFDakMscUJBQXFCLEVBQUUsbUNBQTBCO0lBQ2pELGtCQUFrQixFQUFFLGdDQUF1QjtJQUMzQyxxQkFBcUIsRUFBRSxtQ0FBMEI7SUFDakQsbUJBQW1CLEVBQUUsaUNBQXdCO0NBQzlDLENBQUM7SUFDQSxZQUFZLFNBQVM7UUFDbkIsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ2pCLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO0lBQzlCLENBQUM7SUFFUyxLQUFLLENBQUMsb0JBQW9CO1FBQ2xDLE1BQU0sZUFBZSxHQUFHLE1BQU0sSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFFOUQsS0FBSyxNQUFNLGFBQWEsSUFBSSxlQUFlLEVBQUUsQ0FBQztZQUM1QyxNQUFNLFlBQVksR0FBRyxlQUFlLENBQUMsSUFBSSxDQUN2QyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsS0FBSyxhQUFhLENBQUMsR0FBRyxDQUM3QyxDQUFDO1lBQ0YsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUNsQixNQUFNLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUN2RCxDQUFDO1FBQ0gs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