create invoice
This commit is contained in:
@@ -10,6 +10,7 @@ import { UpdateOrderStatusDto } from '../dto/update-order-status.dto';
|
||||
import { Permissions } from 'src/common/decorators/permissions.decorator';
|
||||
import { Permission } from 'src/common/enums/permission.enum';
|
||||
import { CreateOrderDto } from '../dto/create-order.dto';
|
||||
import { CreateInvoiceDto } from '../dto/create-invoice.dto';
|
||||
|
||||
@ApiTags('orders')
|
||||
@ApiBearerAuth()
|
||||
@@ -37,18 +38,17 @@ export class OrdersController {
|
||||
@ApiQuery({ name: 'to', required: false, type: Date })
|
||||
@ApiOperation({ summary: 'Get all orders with pagination and filters' })
|
||||
async findAll(@Query() dto: FindOrdersDto, @UserId() userId: string) {
|
||||
const orders=await this.ordersService.findAllForUser(userId, dto);
|
||||
const orders = await this.ordersService.findAllForUser(userId, dto);
|
||||
return orders
|
||||
}
|
||||
|
||||
// @UseGuards(AuthGuard)
|
||||
// @ApiOperation({ summary: 'Get an order By id for User' })
|
||||
// @ApiParam({ name: 'orderId', description: 'Order ID' })
|
||||
|
||||
// @Get('public/orders/:orderId')
|
||||
// findOne(@Param('orderId') orderId: string,) {
|
||||
// return this.ordersService.findOne(orderId,);
|
||||
// }
|
||||
@UseGuards(AuthGuard)
|
||||
@ApiOperation({ summary: 'Create invoice for new order' })
|
||||
@ApiParam({ name: 'orderId', description: 'Order ID' })
|
||||
@Post('admin/orders/:orderId/create-invoice')
|
||||
createInvoice(@Param('orderId') orderId: string, @Body() body: CreateInvoiceDto) {
|
||||
return this.ordersService.createInvoice(orderId, body);
|
||||
}
|
||||
|
||||
// @UseGuards(AuthGuard)
|
||||
// @Patch('public/orders/:id/:status')
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import {
|
||||
IsInt, IsArray, IsNumber,
|
||||
IsNotEmpty,
|
||||
ArrayMinSize
|
||||
} from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
export class InvoiceItemDto {
|
||||
@IsInt()
|
||||
@ApiProperty()
|
||||
orderItemId: bigint;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
unitPrice: number
|
||||
|
||||
}
|
||||
|
||||
export class CreateInvoiceDto {
|
||||
@IsArray()
|
||||
@ApiProperty({
|
||||
isArray: true, type: [InvoiceItemDto], example: [
|
||||
{
|
||||
productId: 1,
|
||||
quantity: 100,
|
||||
attributesValues: []
|
||||
}
|
||||
]
|
||||
})
|
||||
@IsNotEmpty()
|
||||
@ArrayMinSize(1, { message: 'At least one product is required' })
|
||||
@Type(() => InvoiceItemDto)
|
||||
items: InvoiceItemDto[];
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
discount: number
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ export class OrderItem extends BaseEntity {
|
||||
@Property({ type: 'decimal', precision: 10, scale: 0 })
|
||||
unitPrice!: number;
|
||||
|
||||
@Property({ type: 'decimal', precision: 10, scale: 0, default: 0 })
|
||||
discount: number = 0;
|
||||
|
||||
@Property({ type: 'decimal', precision: 10, scale: 0 })
|
||||
totalPrice!: number;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export enum OrderStatusEnum {
|
||||
NEW = 'new',
|
||||
INVOICE = 'invoice',
|
||||
INVOICED = 'invoiced',
|
||||
PREPARING = 'preparing',
|
||||
COMPLETED = 'completed',
|
||||
CANCELED = 'canceled',
|
||||
|
||||
@@ -21,6 +21,7 @@ import { ProductRepository } from 'src/modules/product/repositories/product.repo
|
||||
import { TicketService } from 'src/modules/ticket/providers/tickets.service';
|
||||
import { TicketRepository } from 'src/modules/ticket/repositories/tickets.repository';
|
||||
import { TicketStatus } from 'src/modules/ticket/enums/ticket-status.enum';
|
||||
import { CreateInvoiceDto } from '../dto/create-invoice.dto';
|
||||
|
||||
|
||||
@Injectable()
|
||||
@@ -77,7 +78,6 @@ export class OrdersService {
|
||||
const orderItem = this.orderItemRepository.create({
|
||||
order,
|
||||
attributesValues: item.attributesValues,
|
||||
discount: 0,
|
||||
product,
|
||||
quantity: item.quantity,
|
||||
status: OrderItemStatus.PENDING,
|
||||
@@ -108,4 +108,65 @@ export class OrdersService {
|
||||
const orders = await this.orderRepository.findAllPaginated({ userId, ...dto })
|
||||
return orders
|
||||
}
|
||||
|
||||
async findOneOrFail(orderId: string) {
|
||||
const order = await this.orderRepository.findOne({ id: orderId },
|
||||
{ populate: ['items', 'items.product', 'payments'] })
|
||||
if (!order) {
|
||||
throw new BadRequestException('Order not found')
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
async createInvoice(orderId: string, dto: CreateInvoiceDto) {
|
||||
const { items, discount } = dto
|
||||
|
||||
const targetOrder = await this.findOneOrFail(orderId)
|
||||
|
||||
// set price for order items
|
||||
// calculate order financials
|
||||
// change status
|
||||
|
||||
if (items.length !== targetOrder.items.length) {
|
||||
throw new BadRequestException("One or more order items price is not set")
|
||||
}
|
||||
|
||||
|
||||
const order = await this.em.transactional(async (em) => {
|
||||
|
||||
let subTotal = 0
|
||||
// Calculate order item finnicials
|
||||
for (const orderItem of targetOrder.items) {
|
||||
|
||||
const found = items.find(it => it.orderItemId === orderItem.id)
|
||||
if (!found) {
|
||||
throw new BadRequestException(`order item ${orderItem} not found`)
|
||||
}
|
||||
// TODO use Deciaml js to calculation
|
||||
orderItem.unitPrice = found.unitPrice
|
||||
orderItem.totalPrice = (found.unitPrice) * orderItem.quantity
|
||||
|
||||
subTotal += orderItem.totalPrice
|
||||
|
||||
em.persist(orderItem)
|
||||
|
||||
}
|
||||
|
||||
// calculate order financials
|
||||
targetOrder.subTotal = subTotal
|
||||
targetOrder.discount = discount
|
||||
|
||||
targetOrder.total = subTotal - discount
|
||||
|
||||
// change status
|
||||
targetOrder.status = OrderStatusEnum.INVOICED
|
||||
|
||||
em.persist(targetOrder)
|
||||
|
||||
|
||||
return targetOrder
|
||||
})
|
||||
|
||||
return order
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user