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 { Permissions } from 'src/common/decorators/permissions.decorator';
|
||||||
import { Permission } from 'src/common/enums/permission.enum';
|
import { Permission } from 'src/common/enums/permission.enum';
|
||||||
import { CreateOrderDto } from '../dto/create-order.dto';
|
import { CreateOrderDto } from '../dto/create-order.dto';
|
||||||
|
import { CreateInvoiceDto } from '../dto/create-invoice.dto';
|
||||||
|
|
||||||
@ApiTags('orders')
|
@ApiTags('orders')
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@@ -37,18 +38,17 @@ export class OrdersController {
|
|||||||
@ApiQuery({ name: 'to', required: false, type: Date })
|
@ApiQuery({ name: 'to', required: false, type: Date })
|
||||||
@ApiOperation({ summary: 'Get all orders with pagination and filters' })
|
@ApiOperation({ summary: 'Get all orders with pagination and filters' })
|
||||||
async findAll(@Query() dto: FindOrdersDto, @UserId() userId: string) {
|
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
|
return orders
|
||||||
}
|
}
|
||||||
|
|
||||||
// @UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
// @ApiOperation({ summary: 'Get an order By id for User' })
|
@ApiOperation({ summary: 'Create invoice for new order' })
|
||||||
// @ApiParam({ name: 'orderId', description: 'Order ID' })
|
@ApiParam({ name: 'orderId', description: 'Order ID' })
|
||||||
|
@Post('admin/orders/:orderId/create-invoice')
|
||||||
// @Get('public/orders/:orderId')
|
createInvoice(@Param('orderId') orderId: string, @Body() body: CreateInvoiceDto) {
|
||||||
// findOne(@Param('orderId') orderId: string,) {
|
return this.ordersService.createInvoice(orderId, body);
|
||||||
// return this.ordersService.findOne(orderId,);
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// @UseGuards(AuthGuard)
|
// @UseGuards(AuthGuard)
|
||||||
// @Patch('public/orders/:id/:status')
|
// @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 })
|
@Property({ type: 'decimal', precision: 10, scale: 0 })
|
||||||
unitPrice!: number;
|
unitPrice!: number;
|
||||||
|
|
||||||
@Property({ type: 'decimal', precision: 10, scale: 0, default: 0 })
|
|
||||||
discount: number = 0;
|
|
||||||
|
|
||||||
@Property({ type: 'decimal', precision: 10, scale: 0 })
|
@Property({ type: 'decimal', precision: 10, scale: 0 })
|
||||||
totalPrice!: number;
|
totalPrice!: number;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export enum OrderStatusEnum {
|
export enum OrderStatusEnum {
|
||||||
NEW = 'new',
|
NEW = 'new',
|
||||||
INVOICE = 'invoice',
|
INVOICED = 'invoiced',
|
||||||
PREPARING = 'preparing',
|
PREPARING = 'preparing',
|
||||||
COMPLETED = 'completed',
|
COMPLETED = 'completed',
|
||||||
CANCELED = 'canceled',
|
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 { TicketService } from 'src/modules/ticket/providers/tickets.service';
|
||||||
import { TicketRepository } from 'src/modules/ticket/repositories/tickets.repository';
|
import { TicketRepository } from 'src/modules/ticket/repositories/tickets.repository';
|
||||||
import { TicketStatus } from 'src/modules/ticket/enums/ticket-status.enum';
|
import { TicketStatus } from 'src/modules/ticket/enums/ticket-status.enum';
|
||||||
|
import { CreateInvoiceDto } from '../dto/create-invoice.dto';
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -77,7 +78,6 @@ export class OrdersService {
|
|||||||
const orderItem = this.orderItemRepository.create({
|
const orderItem = this.orderItemRepository.create({
|
||||||
order,
|
order,
|
||||||
attributesValues: item.attributesValues,
|
attributesValues: item.attributesValues,
|
||||||
discount: 0,
|
|
||||||
product,
|
product,
|
||||||
quantity: item.quantity,
|
quantity: item.quantity,
|
||||||
status: OrderItemStatus.PENDING,
|
status: OrderItemStatus.PENDING,
|
||||||
@@ -108,4 +108,65 @@ export class OrdersService {
|
|||||||
const orders = await this.orderRepository.findAllPaginated({ userId, ...dto })
|
const orders = await this.orderRepository.findAllPaginated({ userId, ...dto })
|
||||||
return orders
|
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