attribute
This commit is contained in:
@@ -21,6 +21,9 @@ import { CreateCategoryDto } from '../dto/create-category.dto';
|
|||||||
import { CategoryService } from '../providers/category.service';
|
import { CategoryService } from '../providers/category.service';
|
||||||
import { FindCategoriesDto } from '../dto/find-categories.dto';
|
import { FindCategoriesDto } from '../dto/find-categories.dto';
|
||||||
import { UpdateCategoryDto } from '../dto/update-category.dto';
|
import { UpdateCategoryDto } from '../dto/update-category.dto';
|
||||||
|
import { AttributeService } from '../providers/attribute.service';
|
||||||
|
import { CreateAttributeDto } from '../dto/create-attribute.dto';
|
||||||
|
import { UpdateAttributeDto } from '../dto/update-attribute.dto';
|
||||||
|
|
||||||
@ApiTags('products')
|
@ApiTags('products')
|
||||||
@Controller()
|
@Controller()
|
||||||
@@ -28,6 +31,7 @@ export class productController {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly productService: ProductService,
|
private readonly productService: ProductService,
|
||||||
private readonly categoryService: CategoryService,
|
private readonly categoryService: CategoryService,
|
||||||
|
private readonly attributeService: AttributeService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
|
||||||
@@ -159,4 +163,57 @@ export class productController {
|
|||||||
removeCategory(@Param('id') id: string,) {
|
removeCategory(@Param('id') id: string,) {
|
||||||
return this.categoryService.remove(+id);
|
return this.categoryService.remove(+id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*------------------------------ Attibute ------------------------*/
|
||||||
|
@Post('admin/product/:id/attribute')
|
||||||
|
// @UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_productS)
|
||||||
|
@ApiOperation({ summary: 'Create a new category' })
|
||||||
|
@ApiParam({ name: 'id', required: true })
|
||||||
|
@ApiBody({ type: CreateAttributeDto })
|
||||||
|
createAttribute(@Param('id') id: string, @Body() dto: CreateAttributeDto) {
|
||||||
|
return this.attributeService.create(+id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('admin/products/:id/attributes')
|
||||||
|
// @UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_productS)
|
||||||
|
@ApiParam({ name: 'id', required: true })
|
||||||
|
@ApiOperation({ summary: 'Get list of product attributes' })
|
||||||
|
async findProductAttributes(@Param('id') id: string) {
|
||||||
|
return this.attributeService.findAll(+id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('admin/products/attributes/:id')
|
||||||
|
// @UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_productS)
|
||||||
|
@ApiOperation({ summary: 'Get a category by id' })
|
||||||
|
@ApiParam({ name: 'id', required: true })
|
||||||
|
findAttributeById(@Param('id') id: string) {
|
||||||
|
return this.attributeService.findById(+id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch('admin/products/attributes/:id')
|
||||||
|
// @UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_productS)
|
||||||
|
@ApiOperation({ summary: 'Update a attribute' })
|
||||||
|
@ApiParam({ name: 'id', required: true })
|
||||||
|
@ApiBody({ type: UpdateAttributeDto })
|
||||||
|
updateProductAttribute(@Param('id') id: string, @Body() dto: UpdateAttributeDto) {
|
||||||
|
return this.attributeService.update(+id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete('admin/products/attributes/:id')
|
||||||
|
// @UseGuards(AdminAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Permissions(Permission.MANAGE_productS)
|
||||||
|
@ApiOperation({ summary: 'Delete (soft) a attribute' })
|
||||||
|
@ApiParam({ name: 'id', required: true })
|
||||||
|
removeAttribute(@Param('id') id: string,) {
|
||||||
|
return this.attributeService.remove(+id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { IsString, IsOptional, IsBoolean, IsInt, Min, IsEnum } from 'class-validator';
|
||||||
|
import { ApiPropertyOptional, ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import { AttributeType } from '../interface/product.interface';
|
||||||
|
|
||||||
|
export class CreateAttributeDto {
|
||||||
|
@IsString()
|
||||||
|
@ApiProperty({ example: 'نوع روکش' })
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
parentId?: number;
|
||||||
|
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@Type(() => Boolean)
|
||||||
|
@ApiPropertyOptional({ example: true })
|
||||||
|
isRequired: boolean;
|
||||||
|
|
||||||
|
@IsEnum(() => AttributeType)
|
||||||
|
@ApiProperty()
|
||||||
|
type: AttributeType;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
@Type(() => Number)
|
||||||
|
@ApiPropertyOptional({ example: 1 })
|
||||||
|
order?: number;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { PartialType } from '@nestjs/swagger';
|
||||||
|
import { CreateAttributeDto } from './create-attribute.dto';
|
||||||
|
|
||||||
|
export class UpdateAttributeDto extends PartialType(CreateAttributeDto) {
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Entity, Enum, ManyToOne, Property } from '@mikro-orm/core';
|
import { Entity, Enum, ManyToOne, OneToMany, Property } from '@mikro-orm/core';
|
||||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
import { AttributeType } from '../interface/product.interface';
|
import { AttributeType } from '../interface/product.interface';
|
||||||
import { Product } from './product.entity';
|
import { Product } from './product.entity';
|
||||||
@@ -8,6 +8,12 @@ export class Attribute extends BaseEntity {
|
|||||||
@ManyToOne(()=>Product)
|
@ManyToOne(()=>Product)
|
||||||
product: Product
|
product: Product
|
||||||
|
|
||||||
|
@ManyToOne(() => Attribute, { nullable: true })
|
||||||
|
parent?: Attribute | null
|
||||||
|
|
||||||
|
@OneToMany(() => Attribute, (c) => c.parent)
|
||||||
|
children?: Attribute[]
|
||||||
|
|
||||||
@Property({ primary: true })
|
@Property({ primary: true })
|
||||||
id: bigint;
|
id: bigint;
|
||||||
|
|
||||||
@@ -20,4 +26,7 @@ export class Attribute extends BaseEntity {
|
|||||||
@Property({ type: 'boolean', default: false })
|
@Property({ type: 'boolean', default: false })
|
||||||
isRequired: boolean = false;
|
isRequired: boolean = false;
|
||||||
|
|
||||||
|
@Property({ type: 'int', nullable: true })
|
||||||
|
order?: number;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Collection, Entity, ManyToOne, OneToMany, Property } from '@mikro-orm/core';
|
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core';
|
||||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
import { Category } from './category.entity';
|
import { Category } from './category.entity';
|
||||||
import { Attribute } from './attribute.entity';
|
import { Attribute } from './attribute.entity';
|
||||||
@@ -6,7 +6,7 @@ import { Attribute } from './attribute.entity';
|
|||||||
|
|
||||||
@Entity({ tableName: 'products' })
|
@Entity({ tableName: 'products' })
|
||||||
export class Product extends BaseEntity {
|
export class Product extends BaseEntity {
|
||||||
@Property({ primary: true })
|
@PrimaryKey({ type: 'bigint', columnType: 'char(26)', autoincrement: true })
|
||||||
id: bigint
|
id: bigint
|
||||||
|
|
||||||
@ManyToOne(() => Category)
|
@ManyToOne(() => Category)
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import { JwtModule } from '@nestjs/jwt';
|
|||||||
import { UtilsModule } from '../util/utils.module';
|
import { UtilsModule } from '../util/utils.module';
|
||||||
import { CategoryRepository } from './repositories/category.repository';
|
import { CategoryRepository } from './repositories/category.repository';
|
||||||
import { CategoryService } from './providers/category.service';
|
import { CategoryService } from './providers/category.service';
|
||||||
|
import { AttributeRepository } from './repositories/attribute.repository';
|
||||||
|
import { AttributeService } from './providers/attribute.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -21,7 +23,11 @@ import { CategoryService } from './providers/category.service';
|
|||||||
UtilsModule,
|
UtilsModule,
|
||||||
],
|
],
|
||||||
controllers: [productController,],
|
controllers: [productController,],
|
||||||
providers: [ProductService, ProductRepository, CategoryRepository, CategoryService],
|
providers: [ProductService, ProductRepository,
|
||||||
exports: [ProductRepository, CategoryRepository, CategoryService],
|
CategoryRepository, CategoryService,
|
||||||
|
AttributeRepository, AttributeService],
|
||||||
|
exports: [ProductRepository, CategoryRepository,
|
||||||
|
CategoryService, AttributeRepository,
|
||||||
|
AttributeService],
|
||||||
})
|
})
|
||||||
export class productModule { }
|
export class productModule { }
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import { BadGatewayException, Injectable, NotFoundException } from '@nestjs/common';
|
||||||
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
|
import { RequiredEntityData } from '@mikro-orm/core';
|
||||||
|
import { AttributeRepository } from '../repositories/attribute.repository';
|
||||||
|
import { CreateAttributeDto } from '../dto/create-attribute.dto';
|
||||||
|
import { Attribute } from '../entities/attribute.entity';
|
||||||
|
import { ProductRepository } from '../repositories/product.repository';
|
||||||
|
import { UpdateAttributeDto } from '../dto/update-attribute.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AttributeService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly attributeRepository: AttributeRepository,
|
||||||
|
private readonly productRepository: ProductRepository,
|
||||||
|
private readonly em: EntityManager,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async create(productId: number, dto: CreateAttributeDto) {
|
||||||
|
let parent: null | Attribute = null
|
||||||
|
|
||||||
|
const product = await this.productRepository.findOne({ id: productId })
|
||||||
|
if (!product) {
|
||||||
|
throw new BadGatewayException('Product not found')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dto.parentId) {
|
||||||
|
parent = await this.attributeRepository.findOne({ id: dto.parentId })
|
||||||
|
if (!parent) {
|
||||||
|
throw new BadGatewayException('Parent attribute not found')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: RequiredEntityData<Attribute> = {
|
||||||
|
product,
|
||||||
|
name: dto.name,
|
||||||
|
isRequired: dto.isRequired,
|
||||||
|
order: dto.order,
|
||||||
|
type: dto.type,
|
||||||
|
parent
|
||||||
|
};
|
||||||
|
|
||||||
|
const category = this.attributeRepository.create(data)
|
||||||
|
|
||||||
|
await this.em.persistAndFlush(category)
|
||||||
|
|
||||||
|
return category
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(attributeId: number, dto: UpdateAttributeDto) {
|
||||||
|
|
||||||
|
const attribute = await this.attributeRepository.findOne({ id: attributeId })
|
||||||
|
|
||||||
|
if (!attribute) {
|
||||||
|
throw new NotFoundException('Attribute not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dto.parentId) {
|
||||||
|
const parent = await this.attributeRepository.findOne({ id: dto.parentId })
|
||||||
|
if (!parent) {
|
||||||
|
throw new NotFoundException('parent attribute not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.attributeRepository.assign(attribute, { parent })
|
||||||
|
}
|
||||||
|
|
||||||
|
this.attributeRepository.assign(attribute, dto)
|
||||||
|
|
||||||
|
this.em.persistAndFlush(attribute)
|
||||||
|
|
||||||
|
return attribute
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
findAll(productId: number) {
|
||||||
|
return this.attributeRepository.find({ product: { id: productId } });
|
||||||
|
}
|
||||||
|
|
||||||
|
async findById(attributeId: number): Promise<Attribute> {
|
||||||
|
const attribute = await this.attributeRepository.findOne({ id: attributeId },
|
||||||
|
{ populate: ['children', 'product'] });
|
||||||
|
|
||||||
|
if (!attribute) throw new NotFoundException('Attribute not found');
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: number): Promise<void> {
|
||||||
|
const attribute = await this.findById(id);
|
||||||
|
if (!attribute) {
|
||||||
|
throw new NotFoundException('attribute not found');
|
||||||
|
}
|
||||||
|
if (attribute.children && attribute.children.length > 0) {
|
||||||
|
throw new NotFoundException('attribute has children');
|
||||||
|
}
|
||||||
|
attribute.deletedAt = new Date();
|
||||||
|
return await this.em.persistAndFlush(attribute);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
|
||||||
|
import { Attribute } from '../entities/attribute.entity';
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AttributeRepository extends EntityRepository<Attribute> {
|
||||||
|
constructor(readonly em: EntityManager) {
|
||||||
|
super(em, Attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user