update order

This commit is contained in:
2026-01-30 21:01:20 +03:30
parent fde120da3c
commit 5e5eeec5be
12 changed files with 189 additions and 256 deletions
@@ -121,4 +121,14 @@ export class AdminService {
}
return admin
}
async findByIds(adminIds: string[]) {
const admins = await this.adminRepository.find({
id: { $in: adminIds }
})
if (adminIds.length !== admins.length) {
throw new BadRequestException("some admins not found")
}
return admins
}
}
@@ -75,7 +75,7 @@ export class FieldService {
return this.fieldRepository.find({
entityId
},
{ populate: ['options', 'options.value'] });
{ populate: ['options'] });
}
async findById(fieldId: number): Promise<Field> {
@@ -5,7 +5,7 @@ import { AuthGuard } from '../../auth/guards/auth.guard';
import { UserId } from '../../../common/decorators/user-id.decorator';
import { FindOrdersDto } from '../dto/find-orders.dto';
import {
CreateOrderDto, CreateOrderItemAsUserDto,
CreateOrderAsUSerDto, CreateOrderItemAsUserDto,
CreateOrderItemDtoAsAdmin, CreateOrderAsAdminDto
} from '../dto/create-order.dto';
import { AdminId } from 'src/common/decorators/admin-id.decorator';
@@ -23,7 +23,7 @@ export class OrderController {
@Post('public/orders')
@UseGuards(AuthGuard)
@ApiOperation({ summary: 'create order ' })
createOrder(@UserId() userId: string, @Body() body: CreateOrderDto) {
createOrder(@UserId() userId: string, @Body() body: CreateOrderAsUSerDto) {
return this.orderService.createOrderAsUser(userId, body);
}
@@ -111,6 +111,13 @@ export class OrderController {
return this.orderService.updateOrderAsAdmin(orderId, dto);
}
@Patch('admin/orders/:orderId/print-form')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: 'Update Order ' })
updateOrderForPrint(@Param('orderId') orderId: string, @Body() dto: UpdateOrderDtoAsAdmin) {
return this.orderService.updateOrderAsAdmin(orderId, dto);
}
@Delete('admin/orders/:orderId')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: 'Hard Delete Order ' })
@@ -119,11 +126,11 @@ export class OrderController {
}
@Post('admin/orders/:orderId/designer')
@Post('admin/orders/:orderId/item/:itemId/designer')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: 'Assign Order Designer ' })
assignDesigner(@Param('orderId') orderId: string, @Body() body: AssignDesignerDto) {
return this.orderService.assignDesigner(orderId, body.designerId);
assignDesigner(@Param('orderId') orderId: string, @Param('itemId') itemId: string, @Body() body: AssignDesignerDto) {
return this.orderService.assignDesigner(orderId, +itemId, body.designerId);
}
@Post('admin/orders/:orderId/invoice')
+29 -54
View File
@@ -7,12 +7,12 @@ import {
IsBoolean,
IsEnum
} from 'class-validator';
import { ApiPropertyOptional, ApiProperty, OmitType } from '@nestjs/swagger';
import { ApiPropertyOptional, ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { IAttribute, OrderStatusEnum } from '../interface/order.interface';
import { IAttachment, IField, OrderStatusEnum } from '../interface/order.interface';
export class CreateOrderItemDtoAsAdmin {
export class CreateOrderItemAsUserDto {
@IsInt()
@ApiProperty()
productId: number;
@@ -23,7 +23,7 @@ export class CreateOrderItemDtoAsAdmin {
@ApiProperty()
@IsArray()
attributes: IAttribute[]
attributes: IField[]
@ApiPropertyOptional({ example: 'توضیحات' })
@IsString()
@@ -33,6 +33,22 @@ export class CreateOrderItemDtoAsAdmin {
@IsArray()
attachments: { url: string, type: string }[]
}
export class CreateOrderItemDtoAsAdmin extends CreateOrderItemAsUserDto {
@ApiPropertyOptional({ example: [] })
@IsArray()
print?: IField[]
@ApiPropertyOptional({ example: [] })
@IsArray()
printAttachments?: IAttachment[]
@IsInt()
@ApiProperty()
designerId: string;
@ApiProperty()
@IsNumber()
unitPrice: number
@@ -43,10 +59,7 @@ export class CreateOrderItemDtoAsAdmin {
}
export class CreateOrderItemAsUserDto extends OmitType(CreateOrderItemDtoAsAdmin, ['unitPrice', 'discount']) { }
export class CreateOrderDto {
export class CreateOrderAsUSerDto {
@IsArray()
@ApiProperty({
isArray: true, type: [CreateOrderItemAsUserDto], example: [
@@ -55,8 +68,8 @@ export class CreateOrderDto {
quantity: 100,
attributes: [
{
attributeId:1,
value:'string | boolean| number'
attributeId: 1,
value: 'string | boolean| number'
}
],
attachments: [
@@ -72,37 +85,6 @@ export class CreateOrderDto {
items: CreateOrderItemAsUserDto[];
}
export class CreateOrderItemDto {
@IsInt()
@ApiProperty()
productId: number;
@ApiProperty()
@IsNumber()
quantity: number
@ApiProperty()
@IsArray()
attributes: IAttribute[]
@ApiProperty()
@IsNumber()
unitPrice: number
@ApiProperty()
@IsNumber()
discount: number
@ApiPropertyOptional({ example: 'توضیحات' })
@IsString()
description: string
@ApiPropertyOptional({ example: [] })
@IsArray()
@IsString({ each: true })
attachments: { url: string, type: string }[]
}
export class CreateOrderAsAdminDto {
@ApiProperty({ example: '' })
@@ -112,9 +94,12 @@ export class CreateOrderAsAdminDto {
@IsArray()
@ApiProperty({
isArray: true, type: [CreateOrderItemDto], example: [
isArray: true, type: [CreateOrderItemDtoAsAdmin], example: [
{
productId: 1,
designerId: '',
print: [{ fieldId: '', value: '' }],
printAttachments: [{ url: '', type: '' }],
quantity: 100,
attributesValues: []
}
@@ -122,19 +107,9 @@ export class CreateOrderAsAdminDto {
})
@IsNotEmpty()
@ArrayMinSize(1, { message: 'At least one product is required' })
@Type(() => CreateOrderItemDto)
items: CreateOrderItemDto[];
@Type(() => CreateOrderItemDtoAsAdmin)
items: CreateOrderItemDtoAsAdmin[];
@ApiProperty({ example: '' })
@IsString()
@IsNotEmpty()
designerId: string
@ApiProperty({ example: '' })
@IsArray()
@IsString({ each: true })
@IsNotEmpty()
attachments: string[]
@ApiProperty({})
@IsString()
+1 -1
View File
@@ -1,5 +1,5 @@
import { OmitType, PartialType } from '@nestjs/swagger';
import { CreateOrderAsAdminDto, CreateOrderDto } from './create-order.dto';
import { CreateOrderAsAdminDto } from './create-order.dto';
export class UpdateOrderDtoAsAdmin extends PartialType(OmitType(CreateOrderAsAdminDto, 'items' as any)) { }
@@ -2,7 +2,8 @@ import { Entity, Formula, Index, ManyToOne, OptionalProps, PrimaryKey, Property
import { BaseEntity } from '../../../common/entities/base.entity';
import { Order } from './order.entity';
import { Product } from 'src/modules/product/entities/product.entity';
import { IAttribute } from '../interface/order.interface';
import { IAttachment, IField } from '../interface/order.interface';
import { Admin } from 'src/modules/admin/entities/admin.entity';
// import { OrderItemStatus } from '../interface/order.interface';
@Entity({ tableName: 'order_items' })
@@ -19,8 +20,11 @@ export class OrderItem {
@ManyToOne(() => Product)
product!: Product;
@ManyToOne(() => Admin, { nullable: true })
designer?: Admin
@Property({ type: 'json', nullable: true })
attributes?: IAttribute[]
attributes?: IField[]
@Property({ type: 'int' })
quantity!: number;
@@ -49,7 +53,14 @@ export class OrderItem {
adminDescription?: string;
@Property({ type: 'json', nullable: true })
attachments?: { type: string, url: string }[] // user attachments like voice and photos
attachments?: IAttachment[] // user attachments like voice and photos
@Property({ type: 'json', nullable: true })
printAttachments?: IAttachment[]
@Property({ type: 'json', nullable: true })
print?: IField[] // print form selected attributes
@Property({ nullable: true, columnType: 'timestamptz' })
confirmedAt?: Date;
+1 -9
View File
@@ -13,7 +13,7 @@ import {
OptionalProps,
Formula
} from '@mikro-orm/core';
import { OrderStatusEnum } from '../interface/order.interface';
import { IField, OrderStatusEnum } from '../interface/order.interface';
import { User } from '../../user/entities/user.entity';
import { OrderItem } from './order-item.entity';
import { Payment } from 'src/modules/payment/entities/payment.entity';
@@ -52,9 +52,6 @@ export class Order {
@ManyToOne(() => Admin, { nullable: true })
creator?: Admin
@ManyToOne(() => Admin, { nullable: true })
designer?: Admin
@Property({ type: 'int', nullable: true })
orderNumber?: number;
@@ -198,11 +195,6 @@ export class Order {
@Enum(() => OrderStatusEnum)
status!: OrderStatusEnum;
@Property({ type: 'json', nullable: true })
attachments?: string[]
@Property({ type: 'json', nullable: true })
print?: { fieldId: string, value: string }[] // id of field options
@Property({ type: 'string', nullable: true })
paymentMethod?: string;
+33 -35
View File
@@ -1,3 +1,6 @@
import { Admin } from "src/modules/admin/entities/admin.entity"
import { Product } from "src/modules/product/entities/product.entity"
export enum OrderStatusEnum {
CREATED = 'created',
@@ -25,49 +28,44 @@ export enum OrderStatusEnum {
CANCELED = 'canceled',
}
export interface IField { fieldId: number, value: string }
export interface CreateOrderItemParam{
export interface IAttachment { type: string, url: string }
export interface CreateOrderItem {
productId: number,
quantity: number
attributes?: IAttribute[]
attributes?: IField[]
description?: string
attachments?: { url: string, type: string }[]
attachments?: IAttachment[]
unitPrice?: number
discount?: number
}
export interface CreateOrderParam {
userId: string
items: Array<{
productId: number,
quantity: number
attributes: IAttribute[]
description: string
attachments: { url: string, type: string }[]
unitPrice?: number
discount?: number
}>;
status: OrderStatusEnum
//optional
enableTax?: Boolean
attachments?: string[]
paymentMethod?: string
adminId?: string
estimatedDays?: number
print?: IField[]
printAttachments?: IAttachment[]
designerId?: string
}
export type UpdateOrderParam = Partial<Omit<CreateOrderParam, 'items'>>
export interface UpdateOrderItem {
productId?: number,
quantity?: number
attributes?: IAttribute[]
description?: string
attachments?: { url: string, type: string }[]
unitPrice?: number
discount?: number
export type CreateOrderItemPopulated = Omit<CreateOrderItem, 'productId' | 'designerId'> & {
product: Product,
designer?: Admin
}
export interface IAttribute { attributeId: number, value: string | number | boolean }
export interface CreateOrder {
userId: string
status: OrderStatusEnum
enableTax?: Boolean
paymentMethod?: string
adminId?: string
estimatedDays?: number
}
export interface CreateOrderWithItems extends CreateOrder {
items: CreateOrderItem[]
}
export type UpdateOrder = Partial<CreateOrder>
export type UpdateOrderItem = Partial<CreateOrderItemPopulated>
+84 -68
View File
@@ -4,14 +4,19 @@ import { OrderRepository } from '../repositories/order.repository';
import { FindOrdersDto } from '../dto/find-orders.dto';
import { EventEmitter2 } from '@nestjs/event-emitter';
import {
CreateOrderDto, CreateOrderItemAsUserDto,
CreateOrderAsAdminDto,
CreateOrderAsUSerDto, CreateOrderItemAsUserDto,
CreateOrderItemDtoAsAdmin
} from '../dto/create-order.dto';
import { UserService } from 'src/modules/user/providers/user.service';
import {
CreateOrderItemParam,
CreateOrderParam, OrderStatusEnum,
UpdateOrderItem, UpdateOrderParam
CreateOrderItem,
CreateOrder, OrderStatusEnum,
// UpdateOrderItem,
CreateOrderWithItems,
CreateOrderItemPopulated,
UpdateOrder,
UpdateOrderItem
} from '../interface/order.interface';
import { OrderItemRepository } from '../repositories/order-item.repository';
import { ProductService } from 'src/modules/product/providers/product.service';
@@ -26,6 +31,7 @@ import { Admin } from 'src/modules/admin/entities/admin.entity';
import { Product } from 'src/modules/product/entities/product.entity';
import { AdminService } from 'src/modules/admin/providers/admin.service';
import { OrderItem } from '../entities/order-item.entity';
import { UpdateOrderDtoAsAdmin } from '../dto/update-order.dto';
@Injectable()
@@ -47,7 +53,7 @@ export class OrderService {
private readonly paymentRepository: PaymentRepository,
) { }
async createOrderAsAdmin(adminId: string, dto: CreateOrderParam) {
async createOrderAsAdmin(adminId: string, dto: CreateOrderAsAdminDto) {
const order = await this.createOrder({ ...dto, adminId })
// await this.calculateOrder(order)
// this.em.flush()
@@ -56,7 +62,7 @@ export class OrderService {
}
async createOrderAsUser(userId: string, dto: CreateOrderDto) {
async createOrderAsUser(userId: string, dto: CreateOrderAsUSerDto) {
const order = await this.createOrder({ ...dto, userId, status: OrderStatusEnum.CREATED })
this.logger.log("Order created as admin")
return order
@@ -64,10 +70,10 @@ export class OrderService {
}
async updateOrderAsAdmin(orderId: string, param: UpdateOrderParam) {
async updateOrderAsAdmin(orderId: string, dto: UpdateOrderDtoAsAdmin) {
const order = await this.findOrderOrFail(orderId)
const updateOrder = await this.updateOrder(order, param)
const updateOrder = await this.updateOrder(order, dto)
// const updateOrder = await this.calculateOrder(order)
@@ -92,7 +98,7 @@ export class OrderService {
const product = await this.productService.findOneOrFail(dto.productId)
const orderItem = this.createOrderItem(order, product, dto)
const orderItem = this.createOrderItemEntity(order, { ...dto, product })
await this.em.flush()
@@ -105,7 +111,12 @@ export class OrderService {
const product = await this.productService.findOneOrFail(dto.productId)
const orderItem = this.createOrderItem(order, product, dto)
let designer: Admin | undefined
if (dto.designerId) {
designer = await this.adminService.findOrFail(dto.designerId)
}
const orderItem = this.createOrderItemEntity(order, { ...dto, designer, product })
await this.em.flush()
@@ -118,32 +129,32 @@ export class OrderService {
async updateOrderItemAsUser(userId: string, orderId: string, itemId: number, dto: UpdateOrderItemDtoAsUser) {
const order = await this.findOrderOrFail(orderId)
const orderItem = await this.findOrderItemOrFail(orderId,itemId)
if (order.user.id !== userId) {
if (orderItem.order.user.id !== userId) {
throw new BadRequestException(`This order doesnt belongs to you`)
}
if (order.status !== OrderStatusEnum.CREATED) {
throw new BadRequestException(`You can not update when status is ${order.status}`)
if (orderItem.order.status !== OrderStatusEnum.CREATED) {
throw new BadRequestException(`You can not update when status is ${orderItem.order.status}`)
}
const orderItem = await this.updateOrderItem(itemId, dto)
const updated = await this.updateOrderItem(orderItem, dto)
return orderItem
return updated
}
async updateOrderItemAsAdmin(orderId: string, itemId: number, dto: UpdateOrderItemDtoAsAdmin) {
await this.findOrderItemOrFail(orderId, itemId)
const orderItem = await this.findOrderItemOrFail(orderId, itemId)
const orderItem = await this.updateOrderItem(itemId, dto)
const updated = await this.updateOrderItem(orderItem, dto)
// await this.calculateOrder(undefined, orderId)
// await this.em.flush()
return orderItem
return updated
}
async removeOrderItemAsAdmin(orderId: string, itemId: number) {
@@ -237,24 +248,21 @@ export class OrderService {
return orderItem
}
async assignDesigner(orderId: string, designerId: string) {
const order = await this.orderRepository.findOne({ id: orderId })
if (!order) {
throw new BadRequestException("Order not found")
}
async assignDesigner(orderId: string, orderItemId: number, designerId: string) {
const orderItem = await this.findOrderItemOrFail(orderId, orderItemId)
const designer = await this.adminRepository.findOne({ id: designerId })
if (!designer) {
throw new BadRequestException("designer not found")
}
order.designer = designer
// order.status = OrderStatusEnum.IN_DESIGN
orderItem.designer = designer
await this.em.persistAndFlush(orderItem)
await this.em.persistAndFlush(order)
return order
return orderItem
}
@@ -298,45 +306,51 @@ export class OrderService {
// ==================== Entity Methods ====================
private async createOrderItem(order: Order, product: Product, dto: CreateOrderItemParam, em?: EntityManager) {
const { attributes, description, quantity, attachments, discount, unitPrice } = dto
private async createOrderItemEntity(order: Order, dto: CreateOrderItemPopulated, em?: EntityManager) {
const { attributes, description, quantity, attachments, discount,
unitPrice, product, designer, print, printAttachments } = dto
const eM = em ?? this.em
return eM.create(
OrderItem,
{
designer,
order,
attributes,
description,
quantity,
attachments,
discount: discount ?? undefined,
unitPrice: unitPrice ?? undefined,
product
discount,
unitPrice,
product,
print,
printAttachments
})
}
// ==================== Core Logic ====================
async createOrder(dto: CreateOrderParam) {
const { items, userId, attachments, designerId, enableTax,
async createOrder(dto: CreateOrderWithItems) {
const { items, userId, enableTax,
estimatedDays, paymentMethod, status, adminId } = dto
// Validate and fetch all required entities
const user = await this.userService.findOrFail(userId)
const admin = adminId ? await this.adminService.findOrFail(adminId) : undefined
const designer = designerId ? await this.adminService.findOrFail(designerId) : undefined
const products = await this.productService.findProductsByIds(items.map(item => item.productId))
const desiners = await this.adminService.findByIds(items.map(item => item.designerId).filter(id => id != null))
const productMap = new Map(
products.map(p => [Number(p.id), p])
);
const designerMap = new Map(
desiners.map(d => [d.id, d])
)
return this.em.transactional(async (em) => {
const order = em.create(Order, {
creator: admin,
user,
attachments,
designer,
enableTax,
estimatedDays,
paymentMethod,
@@ -351,8 +365,16 @@ export class OrderService {
if (!product) {
throw new BadRequestException("Product not found!")
}
let designer: undefined | Admin = undefined
const orderItem = await this.createOrderItem(order, product, item, em)
if (item.designerId) {
designer = designerMap.get(item.designerId)
if (!designer) {
throw new BadRequestException("designer not found!")
}
}
const orderItem = await this.createOrderItemEntity(order, { ...item, designer, product }, em)
order.items.add(orderItem)
}
@@ -369,8 +391,8 @@ export class OrderService {
}
async updateOrder(order: Order, param: UpdateOrderParam) {
const { attachments, adminId, designerId, enableTax,
async updateOrder(order: Order, param: UpdateOrder) {
const { adminId, enableTax,
estimatedDays, paymentMethod, status, userId } = param
@@ -386,15 +408,6 @@ export class OrderService {
}
if (designerId != undefined && designerId != undefined) {
const designer = await this.adminService.findOrFail(designerId)
order.designer = designer
}
if (attachments != undefined) {
order.attachments = attachments
}
if (enableTax != undefined) {
order.enableTax = enableTax
}
@@ -411,36 +424,31 @@ export class OrderService {
order.status = status
}
await this.em.persistAndFlush(order)
return order
}
async updateOrderItem(itemId: number, dto: UpdateOrderItem) {
const { attributes, description, productId, quantity, attachments, discount, unitPrice } = dto
async updateOrderItem(orderItem: OrderItem, dto: UpdateOrderItem) {
const { attributes, description, product, quantity,
attachments, discount, unitPrice, designer, print, printAttachments } = dto
const orderItem = await this.orderItemRepository.findOne({
id: itemId
})
if (!orderItem) {
throw new BadRequestException(`orderItem not found`)
if (product && orderItem.product.id !== product.id) {
orderItem.product = product
}
// product is changed
if (productId && Number(orderItem.product.id) !== productId) {
const product = await this.productRepository.findOne({ id: productId })
if (!product) {
throw new BadRequestException(`product not found`)
}
orderItem.product = product
if (designer && orderItem.designer?.id !== designer.id) {
orderItem.designer = designer
}
if (attributes) {
orderItem.attributes = attributes
}
if (printAttachments) {
orderItem.printAttachments = printAttachments
}
if (description) {
orderItem.description = description
}
@@ -459,6 +467,14 @@ export class OrderService {
orderItem.unitPrice = unitPrice
}
if (print != undefined) {
orderItem.print = print
}
if (attributes != undefined) {
orderItem.attributes = attributes
}
await this.em.flush()
return orderItem
@@ -9,8 +9,6 @@ export class Product extends BaseEntity {
@ManyToOne(() => Category)
category: Category
@Property({ type: 'json', nullable: true })
attributes?: string[]
@PrimaryKey({ type: 'bigint', autoincrement: true })
id: bigint
@@ -24,8 +22,6 @@ export class Product extends BaseEntity {
@Property({ type: 'json' })
quantities: number[]
// @Property()
// prepareTime: number;
@Property({ type: 'text', nullable: true })
linkUrl?: string;
@@ -1,7 +1,7 @@
import { BadGatewayException, Injectable, NotFoundException } from '@nestjs/common';
import { EntityManager } from '@mikro-orm/postgresql';
import { RequiredEntityData } from '@mikro-orm/core';
import { CategoryMessage, productMessage } from 'src/common/enums/message.enum';
import { CategoryMessage, productMessage } from 'src/common/enums/message.enum';
import { CategoryRepository } from '../repositories/category.repository';
import { CreateCategoryDto } from '../dto/create-category.dto';
import { Category } from '../entities/category.entity';
@@ -12,7 +12,7 @@ import { UpdateCategoryDto } from '../dto/update-category.dto';
export class CategoryService {
constructor(
private readonly categoryRepository: CategoryRepository,
private readonly categoryRepository: CategoryRepository,
private readonly em: EntityManager,
) { }
@@ -7,10 +7,6 @@ import { RequiredEntityData } from '@mikro-orm/core';
import { Product } from '../entities/product.entity';
import { CategoryMessage, productMessage } from 'src/common/enums/message.enum';
import { CategoryRepository } from '../repositories/category.repository';
import { FieldService } from 'src/modules/form-builder/provider/field.service';
import { FieldRepository } from 'src/modules/form-builder/repository/field.repository';
import { Field } from 'src/modules/form-builder/entities/field.entity';
import { Category } from '../entities/category.entity';
@Injectable()
export class ProductService {
@@ -18,7 +14,6 @@ export class ProductService {
constructor(
private readonly productRepository: ProductRepository,
private readonly categoryRepository: CategoryRepository,
private readonly fieldRepository: FieldRepository,
private readonly em: EntityManager,
) { }
@@ -34,7 +29,6 @@ export class ProductService {
order: rest.order ?? null,
title: rest.title,
desc: rest.desc,
// prepareTime: rest.prepareTime ?? 0,
quantities: rest.quantities,
images: rest.images ?? undefined,
linkUrl: rest.linkUrl,
@@ -76,81 +70,15 @@ export class ProductService {
return this.productRepository.findAllPaginated(dto);
}
async findById(productId: string): Promise<
Omit<Product, 'attributes'> & {
attributes: Field[];
category: Category;
}
> {
async findById(productId: string) {
const product = await this.productRepository.findOne({ id: productId },
{ populate: ['category'] });
if (!product) throw new NotFoundException(productMessage.NOT_FOUND);
const attributes = product?.attributes
let fields: Field[] = []
if (attributes && attributes.length) {
fields = await this.fieldRepository.find({
id: { $in: attributes }
},
{ populate: ['options'] })
}
return { ...product, attributes: fields };
return product;
}
// async update( id: string, dto: Partial<CreateproductDto>): Promise<Product> {
// const { categoryId, dailyStock, ...rest } = dto;
// const product = await this.productRepository.findOne({ id, restaurant: { id: } }, { populate: ['restaurant'] });
// if (!product) {
// throw new NotFoundException(productMessage.NOT_FOUND);
// }
// // attach new categories if provided (adds, does not attempt to preserve/remove existing ones)
// if (categoryId) {
// const category = await this.categoryRepository.findOne({ id: categoryId, restaurant: { id: } });
// if (!category) {
// throw new NotFoundException(CategoryMessage.NOT_FOUND);
// }
// this.em.assign(product, { category: category });
// }
// // assign other fields from DTO (excluding dailyStock handled below)
// this.em.assign(product, rest);
// // Persist product and update/create related inventory atomically
// await this.em.transactional(async em => {
// await em.persistAndFlush(product);
// if (typeof dailyStock !== 'undefined') {
// const inventoryRecord = await em.findOne(Inventory, { product: product });
// if (inventoryRecord) {
// inventoryRecord.totalStock = dailyStock;
// } else {
// em.create(Inventory, {
// product: product,
// availableStock: dailyStock,
// totalStock: dailyStock,
// });
// }
// }
// await em.flush();
// });
// // Re-load the product to ensure populated relations and stable instance
// const savedproduct = await this.productRepository.findOne({ id: product.id }, { populate: ['category', 'restaurant'] });
// // Invalidate cache for the restaurant if present (optional)
// // await this.invalidateRestaurantproductsCache(savedproduct?.restaurant?.slug);
// return savedproduct ?? product;
// }
async remove(id: string): Promise<void> {
const product = await this.productRepository.findOne({ id });
if (!product) {