update order
This commit is contained in:
@@ -121,4 +121,14 @@ export class AdminService {
|
|||||||
}
|
}
|
||||||
return admin
|
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({
|
return this.fieldRepository.find({
|
||||||
entityId
|
entityId
|
||||||
},
|
},
|
||||||
{ populate: ['options', 'options.value'] });
|
{ populate: ['options'] });
|
||||||
}
|
}
|
||||||
|
|
||||||
async findById(fieldId: number): Promise<Field> {
|
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 { UserId } from '../../../common/decorators/user-id.decorator';
|
||||||
import { FindOrdersDto } from '../dto/find-orders.dto';
|
import { FindOrdersDto } from '../dto/find-orders.dto';
|
||||||
import {
|
import {
|
||||||
CreateOrderDto, CreateOrderItemAsUserDto,
|
CreateOrderAsUSerDto, CreateOrderItemAsUserDto,
|
||||||
CreateOrderItemDtoAsAdmin, CreateOrderAsAdminDto
|
CreateOrderItemDtoAsAdmin, CreateOrderAsAdminDto
|
||||||
} from '../dto/create-order.dto';
|
} from '../dto/create-order.dto';
|
||||||
import { AdminId } from 'src/common/decorators/admin-id.decorator';
|
import { AdminId } from 'src/common/decorators/admin-id.decorator';
|
||||||
@@ -23,7 +23,7 @@ export class OrderController {
|
|||||||
@Post('public/orders')
|
@Post('public/orders')
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
@ApiOperation({ summary: 'create order ' })
|
@ApiOperation({ summary: 'create order ' })
|
||||||
createOrder(@UserId() userId: string, @Body() body: CreateOrderDto) {
|
createOrder(@UserId() userId: string, @Body() body: CreateOrderAsUSerDto) {
|
||||||
return this.orderService.createOrderAsUser(userId, body);
|
return this.orderService.createOrderAsUser(userId, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +111,13 @@ export class OrderController {
|
|||||||
return this.orderService.updateOrderAsAdmin(orderId, dto);
|
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')
|
@Delete('admin/orders/:orderId')
|
||||||
@UseGuards(AdminAuthGuard)
|
@UseGuards(AdminAuthGuard)
|
||||||
@ApiOperation({ summary: 'Hard Delete Order ' })
|
@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)
|
@UseGuards(AdminAuthGuard)
|
||||||
@ApiOperation({ summary: 'Assign Order Designer ' })
|
@ApiOperation({ summary: 'Assign Order Designer ' })
|
||||||
assignDesigner(@Param('orderId') orderId: string, @Body() body: AssignDesignerDto) {
|
assignDesigner(@Param('orderId') orderId: string, @Param('itemId') itemId: string, @Body() body: AssignDesignerDto) {
|
||||||
return this.orderService.assignDesigner(orderId, body.designerId);
|
return this.orderService.assignDesigner(orderId, +itemId, body.designerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('admin/orders/:orderId/invoice')
|
@Post('admin/orders/:orderId/invoice')
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import {
|
|||||||
IsBoolean,
|
IsBoolean,
|
||||||
IsEnum
|
IsEnum
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { ApiPropertyOptional, ApiProperty, OmitType } from '@nestjs/swagger';
|
import { ApiPropertyOptional, ApiProperty } from '@nestjs/swagger';
|
||||||
import { Type } from 'class-transformer';
|
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()
|
@IsInt()
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
productId: number;
|
productId: number;
|
||||||
@@ -23,7 +23,7 @@ export class CreateOrderItemDtoAsAdmin {
|
|||||||
|
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
@IsArray()
|
@IsArray()
|
||||||
attributes: IAttribute[]
|
attributes: IField[]
|
||||||
|
|
||||||
@ApiPropertyOptional({ example: 'توضیحات' })
|
@ApiPropertyOptional({ example: 'توضیحات' })
|
||||||
@IsString()
|
@IsString()
|
||||||
@@ -33,6 +33,22 @@ export class CreateOrderItemDtoAsAdmin {
|
|||||||
@IsArray()
|
@IsArray()
|
||||||
attachments: { url: string, type: string }[]
|
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()
|
@ApiProperty()
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
unitPrice: number
|
unitPrice: number
|
||||||
@@ -43,10 +59,7 @@ export class CreateOrderItemDtoAsAdmin {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CreateOrderItemAsUserDto extends OmitType(CreateOrderItemDtoAsAdmin, ['unitPrice', 'discount']) { }
|
export class CreateOrderAsUSerDto {
|
||||||
|
|
||||||
|
|
||||||
export class CreateOrderDto {
|
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
isArray: true, type: [CreateOrderItemAsUserDto], example: [
|
isArray: true, type: [CreateOrderItemAsUserDto], example: [
|
||||||
@@ -55,8 +68,8 @@ export class CreateOrderDto {
|
|||||||
quantity: 100,
|
quantity: 100,
|
||||||
attributes: [
|
attributes: [
|
||||||
{
|
{
|
||||||
attributeId:1,
|
attributeId: 1,
|
||||||
value:'string | boolean| number'
|
value: 'string | boolean| number'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
attachments: [
|
attachments: [
|
||||||
@@ -72,37 +85,6 @@ export class CreateOrderDto {
|
|||||||
items: CreateOrderItemAsUserDto[];
|
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 {
|
export class CreateOrderAsAdminDto {
|
||||||
@ApiProperty({ example: '' })
|
@ApiProperty({ example: '' })
|
||||||
@@ -112,9 +94,12 @@ export class CreateOrderAsAdminDto {
|
|||||||
|
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
isArray: true, type: [CreateOrderItemDto], example: [
|
isArray: true, type: [CreateOrderItemDtoAsAdmin], example: [
|
||||||
{
|
{
|
||||||
productId: 1,
|
productId: 1,
|
||||||
|
designerId: '',
|
||||||
|
print: [{ fieldId: '', value: '' }],
|
||||||
|
printAttachments: [{ url: '', type: '' }],
|
||||||
quantity: 100,
|
quantity: 100,
|
||||||
attributesValues: []
|
attributesValues: []
|
||||||
}
|
}
|
||||||
@@ -122,19 +107,9 @@ export class CreateOrderAsAdminDto {
|
|||||||
})
|
})
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@ArrayMinSize(1, { message: 'At least one product is required' })
|
@ArrayMinSize(1, { message: 'At least one product is required' })
|
||||||
@Type(() => CreateOrderItemDto)
|
@Type(() => CreateOrderItemDtoAsAdmin)
|
||||||
items: CreateOrderItemDto[];
|
items: CreateOrderItemDtoAsAdmin[];
|
||||||
|
|
||||||
@ApiProperty({ example: '' })
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
designerId: string
|
|
||||||
|
|
||||||
@ApiProperty({ example: '' })
|
|
||||||
@IsArray()
|
|
||||||
@IsString({ each: true })
|
|
||||||
@IsNotEmpty()
|
|
||||||
attachments: string[]
|
|
||||||
|
|
||||||
@ApiProperty({})
|
@ApiProperty({})
|
||||||
@IsString()
|
@IsString()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { OmitType, PartialType } from '@nestjs/swagger';
|
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)) { }
|
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 { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
import { Order } from './order.entity';
|
import { Order } from './order.entity';
|
||||||
import { Product } from 'src/modules/product/entities/product.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';
|
// import { OrderItemStatus } from '../interface/order.interface';
|
||||||
|
|
||||||
@Entity({ tableName: 'order_items' })
|
@Entity({ tableName: 'order_items' })
|
||||||
@@ -19,8 +20,11 @@ export class OrderItem {
|
|||||||
@ManyToOne(() => Product)
|
@ManyToOne(() => Product)
|
||||||
product!: Product;
|
product!: Product;
|
||||||
|
|
||||||
|
@ManyToOne(() => Admin, { nullable: true })
|
||||||
|
designer?: Admin
|
||||||
|
|
||||||
@Property({ type: 'json', nullable: true })
|
@Property({ type: 'json', nullable: true })
|
||||||
attributes?: IAttribute[]
|
attributes?: IField[]
|
||||||
|
|
||||||
@Property({ type: 'int' })
|
@Property({ type: 'int' })
|
||||||
quantity!: number;
|
quantity!: number;
|
||||||
@@ -49,7 +53,14 @@ export class OrderItem {
|
|||||||
adminDescription?: string;
|
adminDescription?: string;
|
||||||
|
|
||||||
@Property({ type: 'json', nullable: true })
|
@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' })
|
@Property({ nullable: true, columnType: 'timestamptz' })
|
||||||
confirmedAt?: Date;
|
confirmedAt?: Date;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
OptionalProps,
|
OptionalProps,
|
||||||
Formula
|
Formula
|
||||||
} from '@mikro-orm/core';
|
} 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 { User } from '../../user/entities/user.entity';
|
||||||
import { OrderItem } from './order-item.entity';
|
import { OrderItem } from './order-item.entity';
|
||||||
import { Payment } from 'src/modules/payment/entities/payment.entity';
|
import { Payment } from 'src/modules/payment/entities/payment.entity';
|
||||||
@@ -52,9 +52,6 @@ export class Order {
|
|||||||
@ManyToOne(() => Admin, { nullable: true })
|
@ManyToOne(() => Admin, { nullable: true })
|
||||||
creator?: Admin
|
creator?: Admin
|
||||||
|
|
||||||
@ManyToOne(() => Admin, { nullable: true })
|
|
||||||
designer?: Admin
|
|
||||||
|
|
||||||
|
|
||||||
@Property({ type: 'int', nullable: true })
|
@Property({ type: 'int', nullable: true })
|
||||||
orderNumber?: number;
|
orderNumber?: number;
|
||||||
@@ -198,11 +195,6 @@ export class Order {
|
|||||||
@Enum(() => OrderStatusEnum)
|
@Enum(() => OrderStatusEnum)
|
||||||
status!: 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 })
|
@Property({ type: 'string', nullable: true })
|
||||||
paymentMethod?: string;
|
paymentMethod?: string;
|
||||||
|
|||||||
@@ -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 {
|
export enum OrderStatusEnum {
|
||||||
CREATED = 'created',
|
CREATED = 'created',
|
||||||
|
|
||||||
@@ -25,49 +28,44 @@ export enum OrderStatusEnum {
|
|||||||
CANCELED = 'canceled',
|
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
|
quantity: number
|
||||||
attributes?: IAttribute[]
|
attributes?: IField[]
|
||||||
description?: string
|
description?: string
|
||||||
attachments?: { url: string, type: string }[]
|
attachments?: IAttachment[]
|
||||||
unitPrice?: number
|
unitPrice?: number
|
||||||
discount?: number
|
discount?: number
|
||||||
}
|
|
||||||
|
|
||||||
|
print?: IField[]
|
||||||
export interface CreateOrderParam {
|
printAttachments?: IAttachment[]
|
||||||
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
|
|
||||||
designerId?: string
|
designerId?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UpdateOrderParam = Partial<Omit<CreateOrderParam, 'items'>>
|
export type CreateOrderItemPopulated = Omit<CreateOrderItem, 'productId' | 'designerId'> & {
|
||||||
|
product: Product,
|
||||||
|
designer?: Admin
|
||||||
export interface UpdateOrderItem {
|
|
||||||
productId?: number,
|
|
||||||
quantity?: number
|
|
||||||
attributes?: IAttribute[]
|
|
||||||
description?: string
|
|
||||||
attachments?: { url: string, type: string }[]
|
|
||||||
unitPrice?: number
|
|
||||||
discount?: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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>
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,19 @@ import { OrderRepository } from '../repositories/order.repository';
|
|||||||
import { FindOrdersDto } from '../dto/find-orders.dto';
|
import { FindOrdersDto } from '../dto/find-orders.dto';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import {
|
import {
|
||||||
CreateOrderDto, CreateOrderItemAsUserDto,
|
CreateOrderAsAdminDto,
|
||||||
|
CreateOrderAsUSerDto, CreateOrderItemAsUserDto,
|
||||||
CreateOrderItemDtoAsAdmin
|
CreateOrderItemDtoAsAdmin
|
||||||
} from '../dto/create-order.dto';
|
} from '../dto/create-order.dto';
|
||||||
import { UserService } from 'src/modules/user/providers/user.service';
|
import { UserService } from 'src/modules/user/providers/user.service';
|
||||||
import {
|
import {
|
||||||
CreateOrderItemParam,
|
CreateOrderItem,
|
||||||
CreateOrderParam, OrderStatusEnum,
|
CreateOrder, OrderStatusEnum,
|
||||||
UpdateOrderItem, UpdateOrderParam
|
// UpdateOrderItem,
|
||||||
|
CreateOrderWithItems,
|
||||||
|
CreateOrderItemPopulated,
|
||||||
|
UpdateOrder,
|
||||||
|
UpdateOrderItem
|
||||||
} from '../interface/order.interface';
|
} from '../interface/order.interface';
|
||||||
import { OrderItemRepository } from '../repositories/order-item.repository';
|
import { OrderItemRepository } from '../repositories/order-item.repository';
|
||||||
import { ProductService } from 'src/modules/product/providers/product.service';
|
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 { Product } from 'src/modules/product/entities/product.entity';
|
||||||
import { AdminService } from 'src/modules/admin/providers/admin.service';
|
import { AdminService } from 'src/modules/admin/providers/admin.service';
|
||||||
import { OrderItem } from '../entities/order-item.entity';
|
import { OrderItem } from '../entities/order-item.entity';
|
||||||
|
import { UpdateOrderDtoAsAdmin } from '../dto/update-order.dto';
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -47,7 +53,7 @@ export class OrderService {
|
|||||||
private readonly paymentRepository: PaymentRepository,
|
private readonly paymentRepository: PaymentRepository,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
async createOrderAsAdmin(adminId: string, dto: CreateOrderParam) {
|
async createOrderAsAdmin(adminId: string, dto: CreateOrderAsAdminDto) {
|
||||||
const order = await this.createOrder({ ...dto, adminId })
|
const order = await this.createOrder({ ...dto, adminId })
|
||||||
// await this.calculateOrder(order)
|
// await this.calculateOrder(order)
|
||||||
// this.em.flush()
|
// 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 })
|
const order = await this.createOrder({ ...dto, userId, status: OrderStatusEnum.CREATED })
|
||||||
this.logger.log("Order created as admin")
|
this.logger.log("Order created as admin")
|
||||||
return order
|
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 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)
|
// const updateOrder = await this.calculateOrder(order)
|
||||||
|
|
||||||
@@ -92,7 +98,7 @@ export class OrderService {
|
|||||||
|
|
||||||
const product = await this.productService.findOneOrFail(dto.productId)
|
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()
|
await this.em.flush()
|
||||||
|
|
||||||
@@ -105,7 +111,12 @@ export class OrderService {
|
|||||||
|
|
||||||
const product = await this.productService.findOneOrFail(dto.productId)
|
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()
|
await this.em.flush()
|
||||||
|
|
||||||
@@ -118,32 +129,32 @@ export class OrderService {
|
|||||||
|
|
||||||
async updateOrderItemAsUser(userId: string, orderId: string, itemId: number, dto: UpdateOrderItemDtoAsUser) {
|
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`)
|
throw new BadRequestException(`This order doesnt belongs to you`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (order.status !== OrderStatusEnum.CREATED) {
|
if (orderItem.order.status !== OrderStatusEnum.CREATED) {
|
||||||
throw new BadRequestException(`You can not update when status is ${order.status}`)
|
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) {
|
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.calculateOrder(undefined, orderId)
|
||||||
|
|
||||||
// await this.em.flush()
|
// await this.em.flush()
|
||||||
|
|
||||||
return orderItem
|
return updated
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeOrderItemAsAdmin(orderId: string, itemId: number) {
|
async removeOrderItemAsAdmin(orderId: string, itemId: number) {
|
||||||
@@ -237,24 +248,21 @@ export class OrderService {
|
|||||||
return orderItem
|
return orderItem
|
||||||
}
|
}
|
||||||
|
|
||||||
async assignDesigner(orderId: string, designerId: string) {
|
async assignDesigner(orderId: string, orderItemId: number, designerId: string) {
|
||||||
const order = await this.orderRepository.findOne({ id: orderId })
|
|
||||||
if (!order) {
|
const orderItem = await this.findOrderItemOrFail(orderId, orderItemId)
|
||||||
throw new BadRequestException("Order not found")
|
|
||||||
}
|
|
||||||
const designer = await this.adminRepository.findOne({ id: designerId })
|
const designer = await this.adminRepository.findOne({ id: designerId })
|
||||||
|
|
||||||
if (!designer) {
|
if (!designer) {
|
||||||
throw new BadRequestException("designer not found")
|
throw new BadRequestException("designer not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
order.designer = designer
|
orderItem.designer = designer
|
||||||
// order.status = OrderStatusEnum.IN_DESIGN
|
|
||||||
|
|
||||||
|
await this.em.persistAndFlush(orderItem)
|
||||||
|
|
||||||
await this.em.persistAndFlush(order)
|
return orderItem
|
||||||
|
|
||||||
return order
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,45 +306,51 @@ export class OrderService {
|
|||||||
|
|
||||||
// ==================== Entity Methods ====================
|
// ==================== Entity Methods ====================
|
||||||
|
|
||||||
private async createOrderItem(order: Order, product: Product, dto: CreateOrderItemParam, em?: EntityManager) {
|
private async createOrderItemEntity(order: Order, dto: CreateOrderItemPopulated, em?: EntityManager) {
|
||||||
const { attributes, description, quantity, attachments, discount, unitPrice } = dto
|
const { attributes, description, quantity, attachments, discount,
|
||||||
|
unitPrice, product, designer, print, printAttachments } = dto
|
||||||
|
|
||||||
const eM = em ?? this.em
|
const eM = em ?? this.em
|
||||||
return eM.create(
|
return eM.create(
|
||||||
OrderItem,
|
OrderItem,
|
||||||
{
|
{
|
||||||
|
designer,
|
||||||
order,
|
order,
|
||||||
attributes,
|
attributes,
|
||||||
description,
|
description,
|
||||||
quantity,
|
quantity,
|
||||||
attachments,
|
attachments,
|
||||||
discount: discount ?? undefined,
|
discount,
|
||||||
unitPrice: unitPrice ?? undefined,
|
unitPrice,
|
||||||
product
|
product,
|
||||||
|
print,
|
||||||
|
printAttachments
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== Core Logic ====================
|
// ==================== Core Logic ====================
|
||||||
|
|
||||||
async createOrder(dto: CreateOrderParam) {
|
async createOrder(dto: CreateOrderWithItems) {
|
||||||
const { items, userId, attachments, designerId, enableTax,
|
const { items, userId, enableTax,
|
||||||
estimatedDays, paymentMethod, status, adminId } = dto
|
estimatedDays, paymentMethod, status, adminId } = dto
|
||||||
|
|
||||||
// Validate and fetch all required entities
|
// Validate and fetch all required entities
|
||||||
const user = await this.userService.findOrFail(userId)
|
const user = await this.userService.findOrFail(userId)
|
||||||
const admin = adminId ? await this.adminService.findOrFail(adminId) : undefined
|
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 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(
|
const productMap = new Map(
|
||||||
products.map(p => [Number(p.id), p])
|
products.map(p => [Number(p.id), p])
|
||||||
);
|
);
|
||||||
|
const designerMap = new Map(
|
||||||
|
desiners.map(d => [d.id, d])
|
||||||
|
)
|
||||||
|
|
||||||
return this.em.transactional(async (em) => {
|
return this.em.transactional(async (em) => {
|
||||||
|
|
||||||
const order = em.create(Order, {
|
const order = em.create(Order, {
|
||||||
creator: admin,
|
creator: admin,
|
||||||
user,
|
user,
|
||||||
attachments,
|
|
||||||
designer,
|
|
||||||
enableTax,
|
enableTax,
|
||||||
estimatedDays,
|
estimatedDays,
|
||||||
paymentMethod,
|
paymentMethod,
|
||||||
@@ -351,8 +365,16 @@ export class OrderService {
|
|||||||
if (!product) {
|
if (!product) {
|
||||||
throw new BadRequestException("Product not found!")
|
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)
|
order.items.add(orderItem)
|
||||||
}
|
}
|
||||||
@@ -369,8 +391,8 @@ export class OrderService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateOrder(order: Order, param: UpdateOrderParam) {
|
async updateOrder(order: Order, param: UpdateOrder) {
|
||||||
const { attachments, adminId, designerId, enableTax,
|
const { adminId, enableTax,
|
||||||
estimatedDays, paymentMethod, status, userId } = param
|
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) {
|
if (enableTax != undefined) {
|
||||||
order.enableTax = enableTax
|
order.enableTax = enableTax
|
||||||
}
|
}
|
||||||
@@ -411,36 +424,31 @@ export class OrderService {
|
|||||||
order.status = status
|
order.status = status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
await this.em.persistAndFlush(order)
|
await this.em.persistAndFlush(order)
|
||||||
|
|
||||||
return order
|
return order
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateOrderItem(itemId: number, dto: UpdateOrderItem) {
|
async updateOrderItem(orderItem: OrderItem, dto: UpdateOrderItem) {
|
||||||
const { attributes, description, productId, quantity, attachments, discount, unitPrice } = dto
|
const { attributes, description, product, quantity,
|
||||||
|
attachments, discount, unitPrice, designer, print, printAttachments } = dto
|
||||||
|
|
||||||
const orderItem = await this.orderItemRepository.findOne({
|
if (product && orderItem.product.id !== product.id) {
|
||||||
id: itemId
|
orderItem.product = product
|
||||||
})
|
|
||||||
|
|
||||||
if (!orderItem) {
|
|
||||||
throw new BadRequestException(`orderItem not found`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// product is changed
|
if (designer && orderItem.designer?.id !== designer.id) {
|
||||||
if (productId && Number(orderItem.product.id) !== productId) {
|
orderItem.designer = designer
|
||||||
const product = await this.productRepository.findOne({ id: productId })
|
|
||||||
|
|
||||||
if (!product) {
|
|
||||||
throw new BadRequestException(`product not found`)
|
|
||||||
}
|
|
||||||
|
|
||||||
orderItem.product = product
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributes) {
|
if (attributes) {
|
||||||
orderItem.attributes = attributes
|
orderItem.attributes = attributes
|
||||||
}
|
}
|
||||||
|
if (printAttachments) {
|
||||||
|
orderItem.printAttachments = printAttachments
|
||||||
|
}
|
||||||
if (description) {
|
if (description) {
|
||||||
orderItem.description = description
|
orderItem.description = description
|
||||||
}
|
}
|
||||||
@@ -459,6 +467,14 @@ export class OrderService {
|
|||||||
orderItem.unitPrice = unitPrice
|
orderItem.unitPrice = unitPrice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (print != undefined) {
|
||||||
|
orderItem.print = print
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributes != undefined) {
|
||||||
|
orderItem.attributes = attributes
|
||||||
|
}
|
||||||
|
|
||||||
await this.em.flush()
|
await this.em.flush()
|
||||||
|
|
||||||
return orderItem
|
return orderItem
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ export class Product extends BaseEntity {
|
|||||||
@ManyToOne(() => Category)
|
@ManyToOne(() => Category)
|
||||||
category: Category
|
category: Category
|
||||||
|
|
||||||
@Property({ type: 'json', nullable: true })
|
|
||||||
attributes?: string[]
|
|
||||||
|
|
||||||
@PrimaryKey({ type: 'bigint', autoincrement: true })
|
@PrimaryKey({ type: 'bigint', autoincrement: true })
|
||||||
id: bigint
|
id: bigint
|
||||||
@@ -24,8 +22,6 @@ export class Product extends BaseEntity {
|
|||||||
@Property({ type: 'json' })
|
@Property({ type: 'json' })
|
||||||
quantities: number[]
|
quantities: number[]
|
||||||
|
|
||||||
// @Property()
|
|
||||||
// prepareTime: number;
|
|
||||||
|
|
||||||
@Property({ type: 'text', nullable: true })
|
@Property({ type: 'text', nullable: true })
|
||||||
linkUrl?: string;
|
linkUrl?: string;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { BadGatewayException, Injectable, NotFoundException } from '@nestjs/common';
|
import { BadGatewayException, Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { EntityManager } from '@mikro-orm/postgresql';
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
import { RequiredEntityData } from '@mikro-orm/core';
|
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 { CategoryRepository } from '../repositories/category.repository';
|
||||||
import { CreateCategoryDto } from '../dto/create-category.dto';
|
import { CreateCategoryDto } from '../dto/create-category.dto';
|
||||||
import { Category } from '../entities/category.entity';
|
import { Category } from '../entities/category.entity';
|
||||||
@@ -12,7 +12,7 @@ import { UpdateCategoryDto } from '../dto/update-category.dto';
|
|||||||
export class CategoryService {
|
export class CategoryService {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly categoryRepository: CategoryRepository,
|
private readonly categoryRepository: CategoryRepository,
|
||||||
private readonly em: EntityManager,
|
private readonly em: EntityManager,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,6 @@ import { RequiredEntityData } from '@mikro-orm/core';
|
|||||||
import { Product } from '../entities/product.entity';
|
import { Product } from '../entities/product.entity';
|
||||||
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 { 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()
|
@Injectable()
|
||||||
export class ProductService {
|
export class ProductService {
|
||||||
@@ -18,7 +14,6 @@ export class ProductService {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly productRepository: ProductRepository,
|
private readonly productRepository: ProductRepository,
|
||||||
private readonly categoryRepository: CategoryRepository,
|
private readonly categoryRepository: CategoryRepository,
|
||||||
private readonly fieldRepository: FieldRepository,
|
|
||||||
private readonly em: EntityManager,
|
private readonly em: EntityManager,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
@@ -34,7 +29,6 @@ export class ProductService {
|
|||||||
order: rest.order ?? null,
|
order: rest.order ?? null,
|
||||||
title: rest.title,
|
title: rest.title,
|
||||||
desc: rest.desc,
|
desc: rest.desc,
|
||||||
// prepareTime: rest.prepareTime ?? 0,
|
|
||||||
quantities: rest.quantities,
|
quantities: rest.quantities,
|
||||||
images: rest.images ?? undefined,
|
images: rest.images ?? undefined,
|
||||||
linkUrl: rest.linkUrl,
|
linkUrl: rest.linkUrl,
|
||||||
@@ -76,81 +70,15 @@ export class ProductService {
|
|||||||
return this.productRepository.findAllPaginated(dto);
|
return this.productRepository.findAllPaginated(dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
async findById(productId: string): Promise<
|
async findById(productId: string) {
|
||||||
Omit<Product, 'attributes'> & {
|
|
||||||
attributes: Field[];
|
|
||||||
category: Category;
|
|
||||||
}
|
|
||||||
> {
|
|
||||||
const product = await this.productRepository.findOne({ id: productId },
|
const product = await this.productRepository.findOne({ id: productId },
|
||||||
{ populate: ['category'] });
|
{ populate: ['category'] });
|
||||||
|
|
||||||
if (!product) throw new NotFoundException(productMessage.NOT_FOUND);
|
if (!product) throw new NotFoundException(productMessage.NOT_FOUND);
|
||||||
|
|
||||||
const attributes = product?.attributes
|
return product;
|
||||||
|
|
||||||
let fields: Field[] = []
|
|
||||||
|
|
||||||
if (attributes && attributes.length) {
|
|
||||||
fields = await this.fieldRepository.find({
|
|
||||||
id: { $in: attributes }
|
|
||||||
},
|
|
||||||
{ populate: ['options'] })
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ...product, attributes: fields };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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> {
|
async remove(id: string): Promise<void> {
|
||||||
const product = await this.productRepository.findOne({ id });
|
const product = await this.productRepository.findOne({ id });
|
||||||
if (!product) {
|
if (!product) {
|
||||||
|
|||||||
Reference in New Issue
Block a user