feat: add product variant management functionality
- Implemented CreateProductVariantDto and UpdateProductVariantDto for product variant data transfer. - Developed ProductVariantsController to handle CRUD operations for product variants. - Created ProductVariantsService to interact with the database using Prisma. - Added ProductVariantsModule to encapsulate the product variant feature. - Included response mapping for consistent API responses.
This commit is contained in:
@@ -1,15 +1,29 @@
|
||||
import { Type } from 'class-transformer'
|
||||
import { IsInt, IsOptional, IsString } from 'class-validator'
|
||||
|
||||
export class CreateProductDto {
|
||||
@IsString()
|
||||
name: string
|
||||
description?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
sku?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
barcode?: string
|
||||
imageUrl?: string
|
||||
attachmentId?: number
|
||||
unit: string
|
||||
discount?: number
|
||||
quantity?: number
|
||||
alertQuantity?: number
|
||||
isActive?: boolean
|
||||
isFeatured?: boolean
|
||||
productInfoId: number
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
brandId?: number
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
categoryId?: number
|
||||
}
|
||||
|
||||
@@ -1,15 +1,30 @@
|
||||
import { Type } from 'class-transformer'
|
||||
import { IsInt, IsOptional, IsString } from 'class-validator'
|
||||
|
||||
export class UpdateProductDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
name?: string
|
||||
description?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
sku?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
barcode?: string
|
||||
imageUrl?: string
|
||||
attachmentId?: number
|
||||
unit?: string
|
||||
discount?: number
|
||||
quantity?: number
|
||||
alertQuantity?: number
|
||||
isActive?: boolean
|
||||
isFeatured?: boolean
|
||||
productInfoId?: number
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
brandId?: number
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
categoryId?: number
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ export class ProductsController {
|
||||
|
||||
@Post()
|
||||
create(@Body() dto: CreateProductDto) {
|
||||
console.log('[ProductController] create called', dto)
|
||||
return this.productsService.create(dto)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,86 @@
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { ResponseMapper } from '../common/response/response-mapper'
|
||||
import { PrismaService } from '../prisma/prisma.service'
|
||||
import { CreateProductDto } from './dto/create-product.dto'
|
||||
|
||||
@Injectable()
|
||||
export class ProductsService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
create(data: any) {
|
||||
return this.prisma.product.create({ data })
|
||||
async create(data: CreateProductDto) {
|
||||
console.log(data)
|
||||
|
||||
// Transform incoming DTO so relation ids are passed as `connect` objects
|
||||
const payload: any = { ...data }
|
||||
// If the client supplied brandId/categoryId (even null), remove the scalar
|
||||
// Prisma expects nested relation objects, so only add `connect` when an id is present.
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'brandId')) {
|
||||
if (payload.brandId !== undefined && payload.brandId !== null) {
|
||||
payload.brand = { connect: { id: Number(payload.brandId) } }
|
||||
}
|
||||
delete payload.brandId
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'categoryId')) {
|
||||
if (payload.categoryId !== undefined && payload.categoryId !== null) {
|
||||
payload.category = { connect: { id: Number(payload.categoryId) } }
|
||||
}
|
||||
delete payload.categoryId
|
||||
}
|
||||
|
||||
const item = await this.prisma.product.create({ data: payload })
|
||||
return ResponseMapper.create(item)
|
||||
}
|
||||
|
||||
findAll() {
|
||||
return this.prisma.product.findMany()
|
||||
async findAll() {
|
||||
const items = await this.prisma.product.findMany({
|
||||
include: { brand: true, category: true },
|
||||
})
|
||||
const mapped = items.map(p => {
|
||||
const { brandId, categoryId, ...rest } = p as any
|
||||
return { ...rest, brand: p.brand, category: p.category }
|
||||
})
|
||||
return ResponseMapper.list(mapped)
|
||||
}
|
||||
|
||||
findOne(id: number) {
|
||||
return this.prisma.product.findUnique({ where: { id } })
|
||||
async findOne(id: number) {
|
||||
const p = await this.prisma.product.findUnique({
|
||||
where: { id },
|
||||
include: { brand: true, category: true },
|
||||
})
|
||||
if (!p) return null
|
||||
|
||||
console.log('first')
|
||||
|
||||
const { brandId, categoryId, ...rest } = p as any
|
||||
return ResponseMapper.single({ ...rest, brand: p.brand, category: p.category })
|
||||
}
|
||||
|
||||
update(id: number, data: any) {
|
||||
return this.prisma.product.update({ where: { id }, data })
|
||||
async update(id: number, data: any) {
|
||||
const payload: any = { ...data }
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'brandId')) {
|
||||
if (payload.brandId === null) {
|
||||
payload.brand = { disconnect: true }
|
||||
} else {
|
||||
payload.brand = { connect: { id: Number(payload.brandId) } }
|
||||
}
|
||||
delete payload.brandId
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'categoryId')) {
|
||||
if (payload.categoryId === null) {
|
||||
payload.category = { disconnect: true }
|
||||
} else {
|
||||
payload.category = { connect: { id: Number(payload.categoryId) } }
|
||||
}
|
||||
delete payload.categoryId
|
||||
}
|
||||
|
||||
const item = await this.prisma.product.update({ where: { id }, data: payload })
|
||||
return ResponseMapper.update(item)
|
||||
}
|
||||
|
||||
remove(id: number) {
|
||||
return this.prisma.product.delete({ where: { id } })
|
||||
async remove(id: number) {
|
||||
const item = await this.prisma.product.delete({ where: { id } })
|
||||
return ResponseMapper.single(item)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user