update order print

This commit is contained in:
2026-07-02 19:49:15 +03:30
parent 56bea20add
commit fdf06b5d88
14 changed files with 189 additions and 63 deletions
@@ -1,5 +1,5 @@
import { Controller, Get, Post, Param, UseGuards, Patch, Query, Body, Delete } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiOkResponse } from '@nestjs/swagger';
import { OrderService } from '../providers/order.service';
import { AuthGuard } from '../../auth/guards/auth.guard';
import { UserId } from '../../../common/decorators/user-id.decorator';
@@ -108,6 +108,7 @@ export class OrderController {
@UseGuards(AdminAuthGuard)
@Permissions(PermissionEnum.CREATE_PRINT)
@ApiOperation({ summary: 'Create order print' })
@ApiOkResponse({ description: 'Order print created or updated' })
createPrint(@Param('orderId') orderId: string, @Body() body: CreateOrderPrintDto) {
return this.orderService.createPrint(orderId, body);
}
@@ -116,6 +117,7 @@ export class OrderController {
@UseGuards(AdminAuthGuard)
@Permissions(PermissionEnum.VIEW_PRINT)
@ApiOperation({ summary: 'Get order print' })
@ApiOkResponse({ description: 'Order print details' })
getPrint(@Param('orderId') orderId: string) {
return this.orderService.getPrint(orderId);
}
+11 -14
View File
@@ -1,19 +1,16 @@
import {
IsArray,
} from 'class-validator';
import { IsArray, ValidateNested } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { IField } from 'src/modules/request/interface/request.interface';
import { Type } from 'class-transformer';
import { OrderPrintValueDto } from './order-print-value.dto';
export class CreateOrderPrintDto {
@ApiProperty({
example: [
{ fieldId: '', value: '' }
]
})
@IsArray()
fields: IField[];
@ApiProperty({
type: [OrderPrintValueDto],
example: [{ fieldId: '', value: '' }],
})
@IsArray()
@ValidateNested({ each: true })
@Type(() => OrderPrintValueDto)
fields: OrderPrintValueDto[];
}
+15
View File
@@ -59,6 +59,21 @@ export class FindOrdersDto {
@IsDateString()
to?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
categoryId?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
userId?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
designerId?: string;
@ApiPropertyOptional({ default: 'createdAt' })
@IsOptional()
@IsString()
@@ -0,0 +1,13 @@
import { IsNotEmpty, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class OrderPrintValueDto {
@ApiProperty({ example: '01HXXXXXXXXXXXXXXXXXXXXX' })
@IsString()
@IsNotEmpty()
fieldId: string;
@ApiProperty({ example: 'some value' })
@IsString()
value: string;
}
@@ -0,0 +1,19 @@
import { Entity, Index, ManyToOne, OptionalProps, Property } from '@mikro-orm/core';
import { BaseEntity } from 'src/common/entities/base.entity';
import { Field } from 'src/modules/form-builder/entities/field.entity';
import { OrderPrint } from './order-print.entity';
@Entity({ tableName: 'order_print_values' })
@Index({ properties: ['orderPrint'] })
export class OrderPrintValue extends BaseEntity {
[OptionalProps]?: 'createdAt' | 'deletedAt';
@ManyToOne(() => OrderPrint)
orderPrint!: OrderPrint;
@ManyToOne(() => Field)
field!: Field;
@Property({ type: 'text' })
value!: string;
}
@@ -1,18 +1,15 @@
import { Entity, Property, OptionalProps, OneToOne } from '@mikro-orm/core';
import { Collection, Entity, OneToMany, OptionalProps, OneToOne } from '@mikro-orm/core';
import { BaseEntity } from 'src/common/entities/base.entity';
import { IField } from 'src/modules/request/interface/request.interface';
import { Order } from './order.entity';
import { OrderPrintValue } from './order-print-value.entity';
@Entity({ tableName: 'order_prints' })
export class OrderPrint extends BaseEntity {
[OptionalProps]?: 'createdAt' | 'deletedAt'
@Property({ type: 'json', nullable: true })
fileds?: IField[]
[OptionalProps]?: 'createdAt' | 'deletedAt';
@OneToMany(() => OrderPrintValue, (value) => value.orderPrint, { orphanRemoval: true })
values = new Collection<OrderPrintValue>(this);
@OneToOne(() => Order, (order) => order.print, { mappedBy: 'print' })
order!: Order
order!: Order;
}
@@ -29,6 +29,18 @@ export enum OrderStatusEnum {
export interface IAttachment { type: string, url: string }
export interface IOrderPrintValue {
fieldId: string;
value: string;
}
export interface IOrderPrintResponse {
id: string;
createdAt: Date;
deletedAt?: Date;
fileds: IOrderPrintValue[];
}
export interface CreateOrder {
userId: string
+4 -2
View File
@@ -4,6 +4,7 @@ import { OrderService } from './providers/order.service';
import { OrderController } from './controllers/order.controller';
import { Order } from './entities/order.entity';
import { OrderPrint } from './entities/order-print.entity';
import { OrderPrintValue } from './entities/order-print-value.entity';
import { AuthModule } from '../auth/auth.module';
import { PaymentModule } from '../payment/payments.module';
import { JwtModule } from '@nestjs/jwt';
@@ -17,10 +18,11 @@ import { UtilsModule } from '../util/utils.module';
import { ProductModule } from '../product/product.module';
import { ChatModule } from '../chat/chat.module';
import { OrderPrintRepository } from './repositories/order-print.repository';
import { OrderPrintValueRepository } from './repositories/order-print-value.repository';
@Module({
imports: [
MikroOrmModule.forFeature([Order, OrderPrint]),
MikroOrmModule.forFeature([Order, OrderPrint, OrderPrintValue]),
AuthModule,
forwardRef(() => PaymentModule),
JwtModule,
@@ -33,7 +35,7 @@ import { OrderPrintRepository } from './repositories/order-print.repository';
],
controllers: [OrderController],
providers: [OrderService, OrderRepository, OrderListeners,
OrdersCrone, OrderPrintRepository],
OrdersCrone, OrderPrintRepository, OrderPrintValueRepository],
exports: [OrderRepository, OrderService],
})
export class OrderModule { }
+67 -17
View File
@@ -7,7 +7,7 @@ import {
CreateOrderAsAdminDto,
} from '../dto/create-order.dto';
import { UserService } from 'src/modules/user/providers/user.service';
import { OrderStatusEnum } from '../interface/order.interface';
import { OrderStatusEnum, IOrderPrintResponse } from '../interface/order.interface';
import { Order } from '../entities/order.entity';
import { AdminService } from 'src/modules/admin/providers/admin.service';
import { UpdateOrderAsAdminDto } from '../dto/update-order.dto';
@@ -19,8 +19,11 @@ import { InvoiceItem } from 'src/modules/invoice/entities/invoice-item.entity';
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
import { UpdateStatusDto } from '../dto/update-status.dto';
import { CreateOrderPrintDto } from '../dto/create-order-print.dto';
import { OrderPrintValueDto } from '../dto/order-print-value.dto';
import { OrderPrint } from '../entities/order-print.entity';
import { OrderPrintValue } from '../entities/order-print-value.entity';
import { OrderPrintRepository } from '../repositories/order-print.repository';
import { Field } from 'src/modules/form-builder/entities/field.entity';
import { Request } from 'src/modules/request/entities/request.entity';
import { Invoice } from 'src/modules/invoice/entities/invoice.entity';
import { OrderCreatedEvent } from '../events/order.events';
@@ -44,7 +47,7 @@ export class OrderService {
let user: User | null = null
if (dto.invoiceItemId) {
invoiceItem = await this.em.findOne(InvoiceItem, { id: dto.invoiceItemId }, { populate: ['invoice', 'invoice.user'] });
invoiceItem = await this.em.findOne(InvoiceItem, { id: dto.invoiceItemId }, { populate: ['invoice', 'invoice.user', 'product'] });
if (!invoiceItem) {
throw new NotFoundException(`Invoice item with ID ${dto.invoiceItemId} not found.`);
}
@@ -86,6 +89,8 @@ export class OrderService {
if (!product) {
throw new NotFoundException(`Product with ID ${dto.productId} not found.`);
}
} else if (invoiceItem?.product) {
product = invoiceItem.product;
}
let designer = null;
@@ -233,29 +238,74 @@ export class OrderService {
return order
}
async createPrint(orderId: string, dto: CreateOrderPrintDto): Promise<OrderPrint> {
const order = await this.findOrderOrFail(orderId);
if (order.print) {
order.print.fileds = dto.fields;
await this.em.flush();
return order.print;
async createPrint(orderId: string, dto: CreateOrderPrintDto): Promise<IOrderPrintResponse> {
const order = await this.em.findOne(Order, { id: orderId }, { populate: ['print'] });
if (!order) {
throw new NotFoundException(`Order with ID ${orderId} not found.`);
}
const print = this.em.create(OrderPrint, {
order,
fileds: dto.fields,
});
const fieldMap = await this.resolvePrintFields(dto.fields);
let print = order.print;
if (print) {
await this.em.populate(print, ['values']);
print.values.removeAll();
} else {
print = this.em.create(OrderPrint, { order });
}
this.assignPrintValues(print, dto.fields, fieldMap);
await this.em.persistAndFlush(print);
return print;
await this.em.populate(print, ['values', 'values.field']);
return this.serializeOrderPrint(print);
}
async getPrint(orderId: string) {
const orderPrint = await this.orderPrintRepository.findOne({ order: { id: orderId } });
async getPrint(orderId: string): Promise<IOrderPrintResponse> {
const orderPrint = await this.orderPrintRepository.findOne(
{ order: { id: orderId } },
{ populate: ['values', 'values.field'] },
);
if (!orderPrint) {
throw new NotFoundException(`Print with ID ${orderId} not found.`);
}
return orderPrint;
return this.serializeOrderPrint(orderPrint);
}
private serializeOrderPrint(print: OrderPrint): IOrderPrintResponse {
return {
id: print.id,
createdAt: print.createdAt,
deletedAt: print.deletedAt,
fileds: print.values.getItems().map((item) => ({
fieldId: item.field.id,
value: item.value,
})),
};
}
private async resolvePrintFields(dtoFields: OrderPrintValueDto[]): Promise<Map<string, Field>> {
const fieldIds = [...new Set(dtoFields.map((field) => field.fieldId))];
const fields = await this.em.find(Field, { id: { $in: fieldIds } });
if (fields.length !== fieldIds.length) {
throw new NotFoundException('One or more fields not found.');
}
return new Map(fields.map((field) => [field.id, field]));
}
private assignPrintValues(
print: OrderPrint,
dtoFields: OrderPrintValueDto[],
fieldMap: Map<string, Field>,
): void {
for (const dtoField of dtoFields) {
print.values.add(
this.em.create(OrderPrintValue, {
orderPrint: print,
field: fieldMap.get(dtoField.fieldId)!,
value: dtoField.value,
}),
);
}
}
// -----------Hrlper Methods -----------
@@ -0,0 +1,10 @@
import { Injectable } from '@nestjs/common';
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
import { OrderPrintValue } from '../entities/order-print-value.entity';
@Injectable()
export class OrderPrintValueRepository extends EntityRepository<OrderPrintValue> {
constructor(readonly em: EntityManager) {
super(em, OrderPrintValue);
}
}
@@ -7,11 +7,9 @@ import { OrderStatusEnum } from '../interface/order.interface';
import { FindOrdersDto } from '../dto/find-orders.dto';
class FindOrdersOpts extends FindOrdersDto {
userId?: string;
adminId?: string;
designerId?: string
};
// class FindOrdersOpts extends FindOrdersDto {
// adminId?: string;
// };
@Injectable()
export class OrderRepository extends EntityRepository<Order> {
@@ -19,7 +17,7 @@ export class OrderRepository extends EntityRepository<Order> {
super(em, Order);
}
async findAllPaginated(opts: FindOrdersOpts): Promise<PaginatedResult<Order>> {
async findAllPaginated(opts: FindOrdersDto): Promise<PaginatedResult<Order>> {
const {
page = 1,
limit = 10,
@@ -30,8 +28,8 @@ export class OrderRepository extends EntityRepository<Order> {
userId,
from,
to,
categoryId,
designerId,
adminId
} = opts;
const offset = (page - 1) * limit;
@@ -63,6 +61,10 @@ export class OrderRepository extends EntityRepository<Order> {
where.designer = { id: designerId };
}
if (categoryId) {
where.type = { id: categoryId };
}
// Filter by date range
if (from || to) {
where.createdAt = {};