This commit is contained in:
@@ -4666,6 +4666,228 @@
|
|||||||
"foreignKeys": {},
|
"foreignKeys": {},
|
||||||
"nativeEnums": {}
|
"nativeEnums": {}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(26)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 26,
|
||||||
|
"mappedType": "character"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"default": "now()",
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"deleted_at": {
|
||||||
|
"name": "deleted_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"is_buyer": {
|
||||||
|
"name": "is_buyer",
|
||||||
|
"type": "boolean",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"default": "false",
|
||||||
|
"mappedType": "boolean"
|
||||||
|
},
|
||||||
|
"food_id": {
|
||||||
|
"name": "food_id",
|
||||||
|
"type": "char(26)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 26,
|
||||||
|
"mappedType": "character"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(26)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 26,
|
||||||
|
"mappedType": "character"
|
||||||
|
},
|
||||||
|
"comment": {
|
||||||
|
"name": "comment",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "text"
|
||||||
|
},
|
||||||
|
"rating": {
|
||||||
|
"name": "rating",
|
||||||
|
"type": "int",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"default": "0",
|
||||||
|
"mappedType": "integer"
|
||||||
|
},
|
||||||
|
"positive_points": {
|
||||||
|
"name": "positive_points",
|
||||||
|
"type": "jsonb",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "json"
|
||||||
|
},
|
||||||
|
"negative_points": {
|
||||||
|
"name": "negative_points",
|
||||||
|
"type": "jsonb",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": true,
|
||||||
|
"mappedType": "json"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "text",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"default": "'pending'",
|
||||||
|
"enumItems": [
|
||||||
|
"pending",
|
||||||
|
"rejected",
|
||||||
|
"approved"
|
||||||
|
],
|
||||||
|
"mappedType": "enum"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "reviews",
|
||||||
|
"schema": "public",
|
||||||
|
"indexes": [
|
||||||
|
{
|
||||||
|
"keyName": "reviews_created_at_index",
|
||||||
|
"columnNames": [
|
||||||
|
"created_at"
|
||||||
|
],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "reviews_deleted_at_index",
|
||||||
|
"columnNames": [
|
||||||
|
"deleted_at"
|
||||||
|
],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "reviews_user_id_index",
|
||||||
|
"columnNames": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "reviews_food_id_status_index",
|
||||||
|
"columnNames": [
|
||||||
|
"food_id",
|
||||||
|
"status"
|
||||||
|
],
|
||||||
|
"composite": true,
|
||||||
|
"constraint": false,
|
||||||
|
"primary": false,
|
||||||
|
"unique": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "reviews_food_id_user_id_unique",
|
||||||
|
"columnNames": [
|
||||||
|
"food_id",
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"composite": true,
|
||||||
|
"constraint": true,
|
||||||
|
"primary": false,
|
||||||
|
"unique": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"keyName": "reviews_pkey",
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": true,
|
||||||
|
"primary": true,
|
||||||
|
"unique": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"checks": [],
|
||||||
|
"foreignKeys": {
|
||||||
|
"reviews_food_id_foreign": {
|
||||||
|
"constraintName": "reviews_food_id_foreign",
|
||||||
|
"columnNames": [
|
||||||
|
"food_id"
|
||||||
|
],
|
||||||
|
"localTableName": "public.reviews",
|
||||||
|
"referencedColumnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"referencedTableName": "public.foods",
|
||||||
|
"updateRule": "cascade"
|
||||||
|
},
|
||||||
|
"reviews_user_id_foreign": {
|
||||||
|
"constraintName": "reviews_user_id_foreign",
|
||||||
|
"columnNames": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"localTableName": "public.reviews",
|
||||||
|
"referencedColumnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"referencedTableName": "public.users",
|
||||||
|
"updateRule": "cascade"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nativeEnums": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
@@ -5501,251 +5723,6 @@
|
|||||||
},
|
},
|
||||||
"nativeEnums": {}
|
"nativeEnums": {}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "char(26)",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": false,
|
|
||||||
"length": 26,
|
|
||||||
"mappedType": "character"
|
|
||||||
},
|
|
||||||
"created_at": {
|
|
||||||
"name": "created_at",
|
|
||||||
"type": "timestamptz",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": false,
|
|
||||||
"length": 6,
|
|
||||||
"default": "now()",
|
|
||||||
"mappedType": "datetime"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"name": "updated_at",
|
|
||||||
"type": "timestamptz",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": false,
|
|
||||||
"length": 6,
|
|
||||||
"default": "now()",
|
|
||||||
"mappedType": "datetime"
|
|
||||||
},
|
|
||||||
"deleted_at": {
|
|
||||||
"name": "deleted_at",
|
|
||||||
"type": "timestamptz",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": true,
|
|
||||||
"length": 6,
|
|
||||||
"mappedType": "datetime"
|
|
||||||
},
|
|
||||||
"order_id": {
|
|
||||||
"name": "order_id",
|
|
||||||
"type": "char(26)",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": false,
|
|
||||||
"length": 26,
|
|
||||||
"mappedType": "character"
|
|
||||||
},
|
|
||||||
"food_id": {
|
|
||||||
"name": "food_id",
|
|
||||||
"type": "char(26)",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": false,
|
|
||||||
"length": 26,
|
|
||||||
"mappedType": "character"
|
|
||||||
},
|
|
||||||
"user_id": {
|
|
||||||
"name": "user_id",
|
|
||||||
"type": "char(26)",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": false,
|
|
||||||
"length": 26,
|
|
||||||
"mappedType": "character"
|
|
||||||
},
|
|
||||||
"comment": {
|
|
||||||
"name": "comment",
|
|
||||||
"type": "text",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": true,
|
|
||||||
"mappedType": "text"
|
|
||||||
},
|
|
||||||
"rating": {
|
|
||||||
"name": "rating",
|
|
||||||
"type": "int",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": false,
|
|
||||||
"default": "0",
|
|
||||||
"mappedType": "integer"
|
|
||||||
},
|
|
||||||
"positive_points": {
|
|
||||||
"name": "positive_points",
|
|
||||||
"type": "jsonb",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": true,
|
|
||||||
"mappedType": "json"
|
|
||||||
},
|
|
||||||
"negative_points": {
|
|
||||||
"name": "negative_points",
|
|
||||||
"type": "jsonb",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": true,
|
|
||||||
"mappedType": "json"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"name": "status",
|
|
||||||
"type": "text",
|
|
||||||
"unsigned": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"primary": false,
|
|
||||||
"nullable": false,
|
|
||||||
"default": "'pending'",
|
|
||||||
"enumItems": [
|
|
||||||
"pending",
|
|
||||||
"rejected",
|
|
||||||
"approved"
|
|
||||||
],
|
|
||||||
"mappedType": "enum"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": "reviews",
|
|
||||||
"schema": "public",
|
|
||||||
"indexes": [
|
|
||||||
{
|
|
||||||
"keyName": "reviews_created_at_index",
|
|
||||||
"columnNames": [
|
|
||||||
"created_at"
|
|
||||||
],
|
|
||||||
"composite": false,
|
|
||||||
"constraint": false,
|
|
||||||
"primary": false,
|
|
||||||
"unique": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keyName": "reviews_deleted_at_index",
|
|
||||||
"columnNames": [
|
|
||||||
"deleted_at"
|
|
||||||
],
|
|
||||||
"composite": false,
|
|
||||||
"constraint": false,
|
|
||||||
"primary": false,
|
|
||||||
"unique": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keyName": "reviews_order_id_index",
|
|
||||||
"columnNames": [
|
|
||||||
"order_id"
|
|
||||||
],
|
|
||||||
"composite": false,
|
|
||||||
"constraint": false,
|
|
||||||
"primary": false,
|
|
||||||
"unique": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keyName": "reviews_user_id_index",
|
|
||||||
"columnNames": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"composite": false,
|
|
||||||
"constraint": false,
|
|
||||||
"primary": false,
|
|
||||||
"unique": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keyName": "reviews_food_id_status_index",
|
|
||||||
"columnNames": [
|
|
||||||
"food_id",
|
|
||||||
"status"
|
|
||||||
],
|
|
||||||
"composite": true,
|
|
||||||
"constraint": false,
|
|
||||||
"primary": false,
|
|
||||||
"unique": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keyName": "reviews_order_id_food_id_user_id_unique",
|
|
||||||
"columnNames": [
|
|
||||||
"order_id",
|
|
||||||
"food_id",
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"composite": true,
|
|
||||||
"constraint": true,
|
|
||||||
"primary": false,
|
|
||||||
"unique": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"keyName": "reviews_pkey",
|
|
||||||
"columnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"composite": false,
|
|
||||||
"constraint": true,
|
|
||||||
"primary": true,
|
|
||||||
"unique": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"checks": [],
|
|
||||||
"foreignKeys": {
|
|
||||||
"reviews_order_id_foreign": {
|
|
||||||
"constraintName": "reviews_order_id_foreign",
|
|
||||||
"columnNames": [
|
|
||||||
"order_id"
|
|
||||||
],
|
|
||||||
"localTableName": "public.reviews",
|
|
||||||
"referencedColumnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"referencedTableName": "public.orders",
|
|
||||||
"updateRule": "cascade"
|
|
||||||
},
|
|
||||||
"reviews_food_id_foreign": {
|
|
||||||
"constraintName": "reviews_food_id_foreign",
|
|
||||||
"columnNames": [
|
|
||||||
"food_id"
|
|
||||||
],
|
|
||||||
"localTableName": "public.reviews",
|
|
||||||
"referencedColumnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"referencedTableName": "public.foods",
|
|
||||||
"updateRule": "cascade"
|
|
||||||
},
|
|
||||||
"reviews_user_id_foreign": {
|
|
||||||
"constraintName": "reviews_user_id_foreign",
|
|
||||||
"columnNames": [
|
|
||||||
"user_id"
|
|
||||||
],
|
|
||||||
"localTableName": "public.reviews",
|
|
||||||
"referencedColumnNames": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"referencedTableName": "public.users",
|
|
||||||
"updateRule": "cascade"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nativeEnums": {}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { Migration } from '@mikro-orm/migrations';
|
||||||
|
|
||||||
|
export class Migration20260715083002_task extends Migration {
|
||||||
|
|
||||||
|
override async up(): Promise<void> {
|
||||||
|
this.addSql(`alter table "reviews" drop constraint "reviews_order_id_foreign";`);
|
||||||
|
|
||||||
|
this.addSql(`drop index "reviews_order_id_index";`);
|
||||||
|
this.addSql(`alter table "reviews" drop constraint "reviews_order_id_food_id_user_id_unique";`);
|
||||||
|
|
||||||
|
this.addSql(`alter table "reviews" add column "is_buyer" boolean not null default false;`);
|
||||||
|
this.addSql(`alter table "reviews" add constraint "reviews_food_id_user_id_unique" unique ("food_id", "user_id");`);
|
||||||
|
}
|
||||||
|
|
||||||
|
override async down(): Promise<void> {
|
||||||
|
this.addSql(`alter table "reviews" drop constraint "reviews_food_id_user_id_unique";`);
|
||||||
|
|
||||||
|
this.addSql(`alter table "reviews" add column "order_id" char(26) not null;`);
|
||||||
|
this.addSql(`alter table "reviews" add constraint "reviews_order_id_foreign" foreign key ("order_id") references "orders" ("id") on update cascade;`);
|
||||||
|
this.addSql(`create index "reviews_order_id_index" on "reviews" ("order_id");`);
|
||||||
|
this.addSql(`alter table "reviews" add constraint "reviews_order_id_food_id_user_id_unique" unique ("order_id", "food_id", "user_id");`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,11 +9,6 @@ export class CreateReviewDto {
|
|||||||
@ApiProperty({ description: 'Food ID' })
|
@ApiProperty({ description: 'Food ID' })
|
||||||
foodId: string;
|
foodId: string;
|
||||||
|
|
||||||
@IsNotEmpty()
|
|
||||||
@IsString()
|
|
||||||
@ApiProperty({ description: 'Order ID' })
|
|
||||||
orderId: string;
|
|
||||||
|
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
@Min(1)
|
@Min(1)
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ import { PositivePoint, NegativePoint } from '../enums/review-point.enum';
|
|||||||
import { ReviewStatus } from '../enums/review-status.enum';
|
import { ReviewStatus } from '../enums/review-status.enum';
|
||||||
|
|
||||||
@Entity({ tableName: 'reviews' })
|
@Entity({ tableName: 'reviews' })
|
||||||
@Unique({ properties: ['order', 'food', 'user'] })
|
@Unique({ properties: ['food', 'user'] })
|
||||||
@Index({ properties: ['food', 'status'] })
|
@Index({ properties: ['food', 'status'] })
|
||||||
@Index({ properties: ['user'] })
|
@Index({ properties: ['user'] })
|
||||||
@Index({ properties: ['order'] })
|
|
||||||
export class Review extends BaseEntity {
|
export class Review extends BaseEntity {
|
||||||
@ManyToOne(() => Order)
|
@Property({ type: 'boolean' })
|
||||||
order: Order;
|
isBuyer: boolean = false
|
||||||
|
|
||||||
@ManyToOne(() => Food)
|
@ManyToOne(() => Food)
|
||||||
food: Food;
|
food: Food;
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ export class ReviewCreatedEvent {
|
|||||||
public readonly userId: string,
|
public readonly userId: string,
|
||||||
public readonly foodId: string,
|
public readonly foodId: string,
|
||||||
public readonly foodName: string,
|
public readonly foodName: string,
|
||||||
public readonly orderId: string,
|
|
||||||
public readonly orderNumber: string | number,
|
|
||||||
public readonly rating: number,
|
public readonly rating: number,
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,13 +46,12 @@ export class ReviewListeners {
|
|||||||
restaurantId: event.restaurantId,
|
restaurantId: event.restaurantId,
|
||||||
message: {
|
message: {
|
||||||
title: NotifTitleEnum.REVIEW_CREATED,
|
title: NotifTitleEnum.REVIEW_CREATED,
|
||||||
content: `نظر جدید برای غذا "${event.foodName}" با امتیاز ${event.rating} از 5 برای سفارش شماره ${event.orderNumber} ثبت شد`,
|
content: `نظر جدید برای غذا "${event.foodName}" با امتیاز ${event.rating} از 5 برای سفارش شماره ثبت شد`,
|
||||||
sms: {
|
sms: {
|
||||||
templateId: this.reviewCreatedSmsTemplateId,
|
templateId: this.reviewCreatedSmsTemplateId,
|
||||||
parameters: {
|
parameters: {
|
||||||
foodName: event.foodName,
|
foodName: event.foodName,
|
||||||
rating: event.rating.toString(),
|
rating: event.rating.toString(),
|
||||||
orderNumber: String(event.orderNumber),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pushNotif: {
|
pushNotif: {
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ import { RequiredEntityData } from '@mikro-orm/core';
|
|||||||
import { Review } from '../entities/review.entity';
|
import { Review } from '../entities/review.entity';
|
||||||
import { FoodMessage, UserMessage, ReviewMessage } from 'src/common/enums/message.enum';
|
import { FoodMessage, UserMessage, ReviewMessage } from 'src/common/enums/message.enum';
|
||||||
import { Order } from '../../orders/entities/order.entity';
|
import { Order } from '../../orders/entities/order.entity';
|
||||||
import { OrderItem } from '../../orders/entities/order-item.entity';
|
|
||||||
import { Restaurant } from 'src/modules/restaurants/entities/restaurant.entity';
|
import { Restaurant } from 'src/modules/restaurants/entities/restaurant.entity';
|
||||||
import { ReviewStatus } from '../enums/review-status.enum';
|
import { ReviewStatus } from '../enums/review-status.enum';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { ReviewCreatedEvent } from '../events/review.events';
|
import { ReviewCreatedEvent } from '../events/review.events';
|
||||||
import { sanitizeText } from '../../utils/sanitize.util';
|
import { sanitizeText } from '../../utils/sanitize.util';
|
||||||
|
import { OrderStatus } from 'src/modules/orders/interface/order.interface';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ReviewService {
|
export class ReviewService {
|
||||||
@@ -28,9 +28,9 @@ export class ReviewService {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
async create(userId: string, createReviewDto: CreateReviewDto): Promise<Review> {
|
async create(userId: string, createReviewDto: CreateReviewDto): Promise<Review> {
|
||||||
const { foodId, orderId, rating, comment, positivePoints, negativePoints } = createReviewDto;
|
const { foodId, rating, comment, positivePoints, negativePoints } = createReviewDto;
|
||||||
|
|
||||||
const food = await this.foodRepository.findOne({ id: foodId });
|
const food = await this.foodRepository.findOne({ id: foodId }, { populate: ['restaurant'] });
|
||||||
if (!food) {
|
if (!food) {
|
||||||
throw new NotFoundException(FoodMessage.NOT_FOUND);
|
throw new NotFoundException(FoodMessage.NOT_FOUND);
|
||||||
}
|
}
|
||||||
@@ -40,34 +40,14 @@ export class ReviewService {
|
|||||||
throw new NotFoundException(UserMessage.USER_NOT_FOUND);
|
throw new NotFoundException(UserMessage.USER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find order and verify it belongs to the user, populate restaurant to get restaurantId
|
const isBuyer = await this.em.count(Order, {
|
||||||
const order = await this.em.findOne(Order, { id: orderId, user: { id: userId } }, { populate: ['restaurant'] });
|
status: OrderStatus.COMPLETED,
|
||||||
if (!order) {
|
items: { food: { id: foodId } },
|
||||||
throw new NotFoundException('Order not found or does not belong to the current user');
|
user: { id: userId }
|
||||||
}
|
}) > 0;
|
||||||
|
|
||||||
// Verify the food is in the order
|
|
||||||
const orderItem = await this.em.findOne(OrderItem, {
|
|
||||||
order: { id: orderId },
|
|
||||||
food: { id: foodId },
|
|
||||||
});
|
|
||||||
if (!orderItem) {
|
|
||||||
throw new BadRequestException('Food is not in the specified order');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user already commented on this food for this order
|
|
||||||
const existingReview = await this.reviewRepository.findOne({
|
|
||||||
order: { id: orderId },
|
|
||||||
food: { id: foodId },
|
|
||||||
user: { id: userId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (existingReview) {
|
|
||||||
throw new BadRequestException(ReviewMessage.ALREADY_COMMENTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data: RequiredEntityData<Review> = {
|
const data: RequiredEntityData<Review> = {
|
||||||
order,
|
isBuyer: true,
|
||||||
food,
|
food,
|
||||||
user,
|
user,
|
||||||
rating,
|
rating,
|
||||||
@@ -92,12 +72,10 @@ export class ReviewService {
|
|||||||
ReviewCreatedEvent.name,
|
ReviewCreatedEvent.name,
|
||||||
new ReviewCreatedEvent(
|
new ReviewCreatedEvent(
|
||||||
review.id,
|
review.id,
|
||||||
order.restaurant.id,
|
food.restaurant.id,
|
||||||
userId,
|
userId,
|
||||||
foodId,
|
foodId,
|
||||||
food.title || 'Unknown Food',
|
food.title || '',
|
||||||
orderId,
|
|
||||||
order.orderNumber || '',
|
|
||||||
rating,
|
rating,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -120,8 +98,8 @@ export class ReviewService {
|
|||||||
|
|
||||||
async findById(id: string, restaurantId: string): Promise<Review> {
|
async findById(id: string, restaurantId: string): Promise<Review> {
|
||||||
const review = await this.reviewRepository.findOne(
|
const review = await this.reviewRepository.findOne(
|
||||||
{ id, order: { restaurant: { id: restaurantId } } },
|
{ id, food: { restaurant: { id: restaurantId } } },
|
||||||
{ populate: ['food', 'user', 'order'] },
|
{ populate: ['food', 'user'] },
|
||||||
);
|
);
|
||||||
if (!review) {
|
if (!review) {
|
||||||
throw new NotFoundException(ReviewMessage.NOT_FOUND);
|
throw new NotFoundException(ReviewMessage.NOT_FOUND);
|
||||||
@@ -130,7 +108,7 @@ export class ReviewService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, userId: string, dto: UpdateReviewDto, isAdmin: boolean = false): Promise<Review> {
|
async update(id: string, userId: string, dto: UpdateReviewDto, isAdmin: boolean = false): Promise<Review> {
|
||||||
const review = await this.reviewRepository.findOne({ id }, { populate: ['food', 'user', 'order'] });
|
const review = await this.reviewRepository.findOne({ id }, { populate: ['food', 'user',] });
|
||||||
if (!review) {
|
if (!review) {
|
||||||
throw new NotFoundException(ReviewMessage.NOT_FOUND);
|
throw new NotFoundException(ReviewMessage.NOT_FOUND);
|
||||||
}
|
}
|
||||||
@@ -165,7 +143,7 @@ export class ReviewService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async changeStatus(reviewId: string, status: ReviewStatus, restaurantId: string): Promise<Review> {
|
async changeStatus(reviewId: string, status: ReviewStatus, restaurantId: string): Promise<Review> {
|
||||||
const review = await this.reviewRepository.findOne({ id: reviewId, order: { restaurant: { id: restaurantId } } });
|
const review = await this.reviewRepository.findOne({ id: reviewId, food: { restaurant: { id: restaurantId } } });
|
||||||
if (!review) {
|
if (!review) {
|
||||||
throw new NotFoundException(ReviewMessage.NOT_FOUND);
|
throw new NotFoundException(ReviewMessage.NOT_FOUND);
|
||||||
}
|
}
|
||||||
@@ -175,7 +153,7 @@ export class ReviewService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string, userId: string, isAdmin: boolean = false) {
|
async remove(id: string, userId: string, isAdmin: boolean = false) {
|
||||||
const review = await this.reviewRepository.findOne({ id }, { populate: ['food', 'user', 'order'] });
|
const review = await this.reviewRepository.findOne({ id }, { populate: ['food', 'user'] });
|
||||||
if (!review) {
|
if (!review) {
|
||||||
throw new NotFoundException(ReviewMessage.NOT_FOUND);
|
throw new NotFoundException(ReviewMessage.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user