This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
import { Migration } from '@mikro-orm/migrations';
|
||||||
|
|
||||||
|
export class Migration20260701150000_addUserGroupsTable extends Migration {
|
||||||
|
|
||||||
|
override async up(): Promise<void> {
|
||||||
|
this.addSql(`
|
||||||
|
create table "user_groups" (
|
||||||
|
"id" char(26) not null,
|
||||||
|
"created_at" timestamptz not null default now(),
|
||||||
|
"updated_at" timestamptz not null default now(),
|
||||||
|
"deleted_at" timestamptz null,
|
||||||
|
"restaurant_id" char(26) not null,
|
||||||
|
"name" varchar(255) not null,
|
||||||
|
"count" int not null default 0,
|
||||||
|
constraint "user_groups_pkey" primary key ("id")
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
this.addSql(`create index "user_groups_created_at_index" on "user_groups" ("created_at");`);
|
||||||
|
this.addSql(`create index "user_groups_deleted_at_index" on "user_groups" ("deleted_at");`);
|
||||||
|
this.addSql(`create index "user_groups_restaurant_id_index" on "user_groups" ("restaurant_id");`);
|
||||||
|
this.addSql(`create unique index "user_groups_restaurant_id_name_unique" on "user_groups" ("restaurant_id", "name") where "deleted_at" is null;`);
|
||||||
|
this.addSql(`
|
||||||
|
alter table "user_groups"
|
||||||
|
add constraint "user_groups_restaurant_id_foreign"
|
||||||
|
foreign key ("restaurant_id") references "restaurants" ("id") on update cascade;
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
override async down(): Promise<void> {
|
||||||
|
this.addSql(`alter table "user_groups" drop constraint if exists "user_groups_restaurant_id_foreign";`);
|
||||||
|
this.addSql(`drop table if exists "user_groups" cascade;`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -767,6 +767,10 @@ export const enum SliderMessage {
|
|||||||
NOT_FOUND = 'اسلایدر یافت نشد',
|
NOT_FOUND = 'اسلایدر یافت نشد',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum UserGroupMessage {
|
||||||
|
NOT_FOUND = 'گروه کاربری یافت نشد',
|
||||||
|
}
|
||||||
|
|
||||||
export const enum InventoryMessage {
|
export const enum InventoryMessage {
|
||||||
AVAILABLE_STOCK_EXCEEDS_TOTAL = 'موجودی موجود نمیتواند از موجودی کل بیشتر باشد',
|
AVAILABLE_STOCK_EXCEEDS_TOTAL = 'موجودی موجود نمیتواند از موجودی کل بیشتر باشد',
|
||||||
FOOD_NOT_FOUND = 'غذا یافت نشد',
|
FOOD_NOT_FOUND = 'غذا یافت نشد',
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { Controller, Get, Post, Body, Patch, Param, Delete, UseGuards } from '@nestjs/common';
|
||||||
|
import {
|
||||||
|
ApiTags,
|
||||||
|
ApiOperation,
|
||||||
|
ApiParam,
|
||||||
|
ApiBody,
|
||||||
|
ApiBearerAuth,
|
||||||
|
} from '@nestjs/swagger';
|
||||||
|
import { UserGroupService } from '../providers/user-group.service';
|
||||||
|
import { CreateUserGroupDto } from '../dto/create-user-group.dto';
|
||||||
|
import { UpdateUserGroupDto } from '../dto/update-user-group.dto';
|
||||||
|
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
||||||
|
import { RestId } from 'src/common/decorators/rest-id.decorator';
|
||||||
|
import { Permission } from 'src/common/enums/permission.enum';
|
||||||
|
import { Permissions } from 'src/common/decorators/permissions.decorator';
|
||||||
|
|
||||||
|
@ApiTags('User Groups')
|
||||||
|
@Controller()
|
||||||
|
export class UserGroupsController {
|
||||||
|
constructor(private readonly userGroupService: UserGroupService) {}
|
||||||
|
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_USERS)
|
||||||
|
@Post('admin/user-groups')
|
||||||
|
@ApiOperation({ summary: 'Create a user group for the restaurant' })
|
||||||
|
@ApiBody({ type: CreateUserGroupDto })
|
||||||
|
create(@Body() dto: CreateUserGroupDto, @RestId() restId: string) {
|
||||||
|
return this.userGroupService.create(restId, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_USERS)
|
||||||
|
@Get('admin/user-groups')
|
||||||
|
@ApiOperation({ summary: 'Get all user groups for the restaurant' })
|
||||||
|
findAll(@RestId() restId: string) {
|
||||||
|
return this.userGroupService.findByRestaurantId(restId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_USERS)
|
||||||
|
@Get('admin/user-groups/:groupId')
|
||||||
|
@ApiOperation({ summary: 'Get a user group by ID' })
|
||||||
|
@ApiParam({ name: 'groupId', description: 'User group ID' })
|
||||||
|
findOne(@Param('groupId') groupId: string, @RestId() restId: string) {
|
||||||
|
return this.userGroupService.findOneOrFail(restId, groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_USERS)
|
||||||
|
@Patch('admin/user-groups/:groupId')
|
||||||
|
@ApiOperation({ summary: 'Update a user group' })
|
||||||
|
@ApiParam({ name: 'groupId', description: 'User group ID' })
|
||||||
|
@ApiBody({ type: UpdateUserGroupDto })
|
||||||
|
update(
|
||||||
|
@Param('groupId') groupId: string,
|
||||||
|
@Body() dto: UpdateUserGroupDto,
|
||||||
|
@RestId() restId: string,
|
||||||
|
) {
|
||||||
|
return this.userGroupService.update(restId, groupId, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_USERS)
|
||||||
|
@Delete('admin/user-groups/:groupId')
|
||||||
|
@ApiOperation({ summary: 'Delete a user group' })
|
||||||
|
@ApiParam({ name: 'groupId', description: 'User group ID' })
|
||||||
|
remove(@Param('groupId') groupId: string, @RestId() restId: string) {
|
||||||
|
return this.userGroupService.remove(restId, groupId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class CreateUserGroupDto {
|
||||||
|
@ApiProperty({ example: 'مشتریان VIP', description: 'Group name' })
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
name!: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { PartialType } from '@nestjs/swagger';
|
||||||
|
import { CreateUserGroupDto } from './create-user-group.dto';
|
||||||
|
|
||||||
|
export class UpdateUserGroupDto extends PartialType(CreateUserGroupDto) {}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { Entity, Index, ManyToOne, Property, Unique } from '@mikro-orm/core';
|
||||||
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
|
import { Restaurant } from '../../restaurants/entities/restaurant.entity';
|
||||||
|
|
||||||
|
@Entity({ tableName: 'user_groups' })
|
||||||
|
@Index({ properties: ['restaurant'] })
|
||||||
|
@Unique({ properties: ['restaurant', 'name'] })
|
||||||
|
export class UserGroup extends BaseEntity {
|
||||||
|
@ManyToOne(() => Restaurant)
|
||||||
|
restaurant!: Restaurant;
|
||||||
|
|
||||||
|
@Property()
|
||||||
|
name!: string;
|
||||||
|
|
||||||
|
@Property({ type: 'integer', default: 0 })
|
||||||
|
count: number = 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
|
import { EntityManager, RequiredEntityData } from '@mikro-orm/postgresql';
|
||||||
|
import { UserGroup } from '../entities/user-group.entity';
|
||||||
|
import { UserGroupRepository } from '../repositories/user-group.repository';
|
||||||
|
import { CreateUserGroupDto } from '../dto/create-user-group.dto';
|
||||||
|
import { UpdateUserGroupDto } from '../dto/update-user-group.dto';
|
||||||
|
import { UserGroupMessage } from 'src/common/enums/message.enum';
|
||||||
|
import { RestaurantsService } from 'src/modules/restaurants/providers/restaurants.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserGroupService {
|
||||||
|
constructor(
|
||||||
|
private readonly userGroupRepository: UserGroupRepository,
|
||||||
|
private readonly restService: RestaurantsService,
|
||||||
|
private readonly em: EntityManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async create(restId: string, dto: CreateUserGroupDto): Promise<UserGroup> {
|
||||||
|
const restaurant = await this.restService.findOneOrFail(restId);
|
||||||
|
|
||||||
|
const data: RequiredEntityData<UserGroup> = {
|
||||||
|
restaurant,
|
||||||
|
name: dto.name,
|
||||||
|
count: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const group = this.userGroupRepository.create(data);
|
||||||
|
await this.em.persistAndFlush(group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
async findByRestaurantId(restId: string): Promise<UserGroup[]> {
|
||||||
|
return this.userGroupRepository.find(
|
||||||
|
{ restaurant: { id: restId } },
|
||||||
|
{ orderBy: { createdAt: 'asc' } },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOneOrFail(restId: string, groupId: string): Promise<UserGroup> {
|
||||||
|
const group = await this.userGroupRepository.findOne({
|
||||||
|
id: groupId,
|
||||||
|
restaurant: { id: restId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!group) {
|
||||||
|
throw new NotFoundException(UserGroupMessage.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(restId: string, groupId: string, dto: UpdateUserGroupDto): Promise<UserGroup> {
|
||||||
|
const group = await this.findOneOrFail(restId, groupId);
|
||||||
|
this.em.assign(group, dto);
|
||||||
|
await this.em.persistAndFlush(group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(restId: string, groupId: string): Promise<void> {
|
||||||
|
const group = await this.findOneOrFail(restId, groupId);
|
||||||
|
group.deletedAt = new Date();
|
||||||
|
await this.em.persistAndFlush(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
|
||||||
|
import { UserGroup } from '../entities/user-group.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserGroupRepository extends EntityRepository<UserGroup> {
|
||||||
|
constructor(readonly em: EntityManager) {
|
||||||
|
super(em, UserGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,17 +15,21 @@ import { PointTransactionRepository } from './repositories/point-transaction.rep
|
|||||||
import { UserRestaurant } from './entities/user-restuarant.entity';
|
import { UserRestaurant } from './entities/user-restuarant.entity';
|
||||||
import { UserRestaurantRepository } from './repositories/user-restuarant.repository';
|
import { UserRestaurantRepository } from './repositories/user-restuarant.repository';
|
||||||
import { UserRestaurantCrone } from './crone/user-restuarant.crone';
|
import { UserRestaurantCrone } from './crone/user-restuarant.crone';
|
||||||
|
import { UserGroup } from './entities/user-group.entity';
|
||||||
|
import { UserGroupRepository } from './repositories/user-group.repository';
|
||||||
|
import { UserGroupService } from './providers/user-group.service';
|
||||||
|
import { UserGroupsController } from './controllers/user-groups.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [UserService, WalletService,
|
providers: [UserService, WalletService, UserGroupService,
|
||||||
UserRepository, WalletTransactionRepository,
|
UserRepository, WalletTransactionRepository,
|
||||||
PointTransactionRepository, UserRestaurantRepository, UserRestaurantCrone],
|
PointTransactionRepository, UserRestaurantRepository, UserGroupRepository, UserRestaurantCrone],
|
||||||
controllers: [UsersController],
|
controllers: [UsersController, UserGroupsController],
|
||||||
imports: [
|
imports: [
|
||||||
MikroOrmModule.forFeature([User, UserAddress, WalletTransaction, PointTransaction, UserRestaurant]),
|
MikroOrmModule.forFeature([User, UserAddress, WalletTransaction, PointTransaction, UserRestaurant, UserGroup]),
|
||||||
JwtModule,
|
JwtModule,
|
||||||
RestaurantsModule,
|
RestaurantsModule,
|
||||||
],
|
],
|
||||||
exports: [UserService, WalletService, UserRepository, WalletTransactionRepository, PointTransactionRepository],
|
exports: [UserService, WalletService, UserGroupService, UserRepository, WalletTransactionRepository, PointTransactionRepository, UserGroupRepository],
|
||||||
})
|
})
|
||||||
export class UserModule { }
|
export class UserModule { }
|
||||||
|
|||||||
Reference in New Issue
Block a user