order
This commit is contained in:
@@ -5,7 +5,7 @@ import { ulid } from 'ulid';
|
|||||||
@Index({ properties: ['deletedAt'] })
|
@Index({ properties: ['deletedAt'] })
|
||||||
@Index({ properties: ['createdAt'] })
|
@Index({ properties: ['createdAt'] })
|
||||||
export abstract class BaseEntity {
|
export abstract class BaseEntity {
|
||||||
[OptionalProps]?: 'id' | 'createdAt' | 'updatedAt' | 'deletedAt'|'orderNumber';
|
[OptionalProps]?: 'id' | 'createdAt' | 'updatedAt' | 'deletedAt'|'orderNumber'|'children';
|
||||||
|
|
||||||
@PrimaryKey({ type: 'string', columnType: 'char(26)' })
|
@PrimaryKey({ type: 'string', columnType: 'char(26)' })
|
||||||
id: string = ulid();
|
id: string = ulid();
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ import { OrderUserAddress, OrderCarAddress } from '../interface/order.interface'
|
|||||||
import { Payment } from 'src/modules/payments/entities/payment.entity';
|
import { Payment } from 'src/modules/payments/entities/payment.entity';
|
||||||
|
|
||||||
@Entity({ tableName: 'orders' })
|
@Entity({ tableName: 'orders' })
|
||||||
@Unique({ properties: ['shop', 'orderNumber'] })
|
|
||||||
@Index({ properties: ['shop', 'status'] })
|
|
||||||
@Index({ properties: ['user', 'status'] })
|
|
||||||
@Index({ properties: ['shop', 'orderNumber'] })
|
|
||||||
@Index({ properties: ['status'] })
|
|
||||||
export class Order extends BaseEntity {
|
export class Order extends BaseEntity {
|
||||||
@ManyToOne(() => User)
|
@ManyToOne(() => User)
|
||||||
user!: User;
|
user!: User;
|
||||||
@@ -56,7 +51,7 @@ export class Order extends BaseEntity {
|
|||||||
@ManyToOne(() => PaymentMethod)
|
@ManyToOne(() => PaymentMethod)
|
||||||
paymentMethod: PaymentMethod;
|
paymentMethod: PaymentMethod;
|
||||||
|
|
||||||
@Property({ type: 'int', defaultRaw: `nextval('order_number_seq')` })
|
@Property({ type: 'int', autoincrement: true })
|
||||||
orderNumber!: number;
|
orderNumber!: number;
|
||||||
|
|
||||||
@Property({ type: 'decimal', precision: 10, scale: 0, default: 0 })
|
@Property({ type: 'decimal', precision: 10, scale: 0, default: 0 })
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { IsString, IsOptional, IsBoolean, IsInt, Min } from 'class-validator';
|
import { IsString, IsOptional, IsBoolean, IsInt, Min, IsUUID } from 'class-validator';
|
||||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import { Type } from 'class-transformer';
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
@@ -24,4 +24,9 @@ export class CreateCategoryDto {
|
|||||||
@Type(() => Number)
|
@Type(() => Number)
|
||||||
@ApiPropertyOptional({ example: 1 })
|
@ApiPropertyOptional({ example: 1 })
|
||||||
order?: number;
|
order?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsUUID()
|
||||||
|
@ApiPropertyOptional({ example: '123e4567-e89b-12d3-a456-426614174000' })
|
||||||
|
parentId?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Entity, Index, Property, Collection, OneToMany, ManyToOne } from '@mikro-orm/core';
|
import { Entity, Index, Property, Collection, OneToMany, ManyToOne, Cascade } from '@mikro-orm/core';
|
||||||
import { Product } from './product.entity';
|
import { Product } from './product.entity';
|
||||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
import { Shop } from '../../shops/entities/shop.entity';
|
import { Shop } from '../../shops/entities/shop.entity';
|
||||||
@@ -10,6 +10,12 @@ export class Category extends BaseEntity {
|
|||||||
@ManyToOne(() => Category, { nullable: true })
|
@ManyToOne(() => Category, { nullable: true })
|
||||||
parent?: Category
|
parent?: Category
|
||||||
|
|
||||||
|
@OneToMany(() => Category, (cat) => cat.parent, {
|
||||||
|
cascade: [Cascade.ALL],
|
||||||
|
orphanRemoval: true
|
||||||
|
})
|
||||||
|
children: Category[]
|
||||||
|
|
||||||
@Property()
|
@Property()
|
||||||
title!: string;
|
title!: string;
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,23 @@ export class CategoryService {
|
|||||||
if (!shop) {
|
if (!shop) {
|
||||||
throw new NotFoundException(RestMessage.NOT_FOUND);
|
throw new NotFoundException(RestMessage.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let parent: Category | undefined;
|
||||||
|
if (dto.parentId) {
|
||||||
|
const foundParent = await this.categoryRepository.findOne({ id: dto.parentId, shop: { id: shopId } });
|
||||||
|
if (!foundParent) {
|
||||||
|
throw new NotFoundException(CategoryMessage.NOT_FOUND);
|
||||||
|
}
|
||||||
|
parent = foundParent;
|
||||||
|
}
|
||||||
|
|
||||||
const data: RequiredEntityData<Category> = {
|
const data: RequiredEntityData<Category> = {
|
||||||
title: dto.title,
|
title: dto.title,
|
||||||
isActive: dto.isActive ?? true,
|
isActive: dto.isActive ?? true,
|
||||||
shop: shop,
|
shop: shop,
|
||||||
avatarUrl: dto.avatarUrl,
|
avatarUrl: dto.avatarUrl,
|
||||||
|
order: dto.order,
|
||||||
|
parent: parent,
|
||||||
};
|
};
|
||||||
|
|
||||||
const category = this.categoryRepository.create(data);
|
const category = this.categoryRepository.create(data);
|
||||||
@@ -32,23 +44,20 @@ export class CategoryService {
|
|||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAllByShop(slug: string): Promise<Category[]> {
|
async findAllByShop(shopSlug: string): Promise<Category[]> {
|
||||||
const shop = await this.em.findOne(Shop, { slug });
|
|
||||||
if (!shop || !shop.id) {
|
|
||||||
throw new NotFoundException(RestMessage.NOT_FOUND);
|
|
||||||
}
|
|
||||||
return this.categoryRepository.find(
|
return this.categoryRepository.find(
|
||||||
{ shop: shop, isActive: true }, { orderBy: { order: 'ASC' } });
|
{ shop: { slug: shopSlug }, isActive: true, parent: null },
|
||||||
|
{ orderBy: { order: 'ASC' }, populate: ['parent'] });
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAllByShopId(shopId: string): Promise<Category[]> {
|
async findAllByShopId(shopId: string): Promise<Category[]> {
|
||||||
return this.categoryRepository.find(
|
return this.categoryRepository.find(
|
||||||
{ shop: { id: shopId } },
|
{ shop: { id: shopId } },
|
||||||
{ orderBy: { order: 'asc' } });
|
{ orderBy: { order: 'asc' }, populate: ['parent'] });
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOne(shopId: string, id: string): Promise<Category> {
|
async findOne(shopId: string, id: string): Promise<Category> {
|
||||||
const cat = await this.categoryRepository.findOne({ id, shop: { id: shopId } }, { populate: ['products'] });
|
const cat = await this.categoryRepository.findOne({ id, shop: { id: shopId } }, { populate: ['products', 'parent'] });
|
||||||
if (!cat) throw new NotFoundException(CategoryMessage.NOT_FOUND);
|
if (!cat) throw new NotFoundException(CategoryMessage.NOT_FOUND);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -57,17 +66,32 @@ export class CategoryService {
|
|||||||
isActive: cat.isActive,
|
isActive: cat.isActive,
|
||||||
shop: cat.shop,
|
shop: cat.shop,
|
||||||
avatarUrl: cat.avatarUrl,
|
avatarUrl: cat.avatarUrl,
|
||||||
|
order: cat.order,
|
||||||
|
parent: cat.parent,
|
||||||
createdAt: cat.createdAt,
|
createdAt: cat.createdAt,
|
||||||
updatedAt: cat.updatedAt,
|
updatedAt: cat.updatedAt,
|
||||||
products: cat.products.getItems().map(f => ({ id: f.id, title: f.title })),
|
products: cat.products.getItems().map(f => ({ id: f.id, title: f.title })),
|
||||||
} as unknown as Category;
|
} as unknown as Category;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async update(shopId: string, id: string, dto: UpdateCategoryDto): Promise<Category> {
|
async update(shopId: string, id: string, dto: UpdateCategoryDto): Promise<Category> {
|
||||||
const cat = await this.categoryRepository.findOne({ id, shop: { id: shopId } });
|
const cat = await this.categoryRepository.findOne({ id, shop: { id: shopId } });
|
||||||
if (!cat) throw new NotFoundException(CategoryMessage.NOT_FOUND);
|
if (!cat) throw new NotFoundException(CategoryMessage.NOT_FOUND);
|
||||||
this.em.assign(cat, dto);
|
|
||||||
|
// Handle parent relationship update
|
||||||
|
if (dto.parentId !== undefined) {
|
||||||
|
if (dto.parentId) {
|
||||||
|
const parent = await this.categoryRepository.findOne({ id: dto.parentId, shop: { id: shopId } });
|
||||||
|
if (!parent) {
|
||||||
|
throw new NotFoundException(CategoryMessage.NOT_FOUND);
|
||||||
|
}
|
||||||
|
cat.parent = parent;
|
||||||
|
} else {
|
||||||
|
cat.parent = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.em.assign(cat, { ...dto, parentId: undefined }); // Exclude parentId from direct assignment
|
||||||
await this.em.persistAndFlush(cat);
|
await this.em.persistAndFlush(cat);
|
||||||
return cat;
|
return cat;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user