online payment
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
import { Injectable, NotFoundException, BadRequestException, Logger } from '@nestjs/common';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { Order } from '../entities/order.entity';
|
||||
import { OrderItem } from '../entities/order-item.entity';
|
||||
import { User } from '../../user/entities/user.entity';
|
||||
import { PaymentMethodEnum, PaymentStatusEnum } from '../../payment/interface/payment';
|
||||
import { PaymentsService } from '../../payment/services/payments.service';
|
||||
import { OrderRepository } from '../repositories/order.repository';
|
||||
import { FindOrdersDto } from '../dto/find-orders.dto';
|
||||
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
|
||||
import { Payment } from 'src/modules/payment/entities/payment.entity';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events';
|
||||
import { OrderMessage } from 'src/common/enums/message.enum';
|
||||
import { CreateOrderDto } from '../dto/create-order.dto';
|
||||
import { UserService } from 'src/modules/user/providers/user.service';
|
||||
import { OrderItemStatus, OrderStatusEnum } from '../interface/order.interface';
|
||||
import { OrderItemRepository } from '../repositories/order-item.repository';
|
||||
import { ProductService } from 'src/modules/product/providers/product.service';
|
||||
import { ProductRepository } from 'src/modules/product/repositories/product.repository';
|
||||
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()
|
||||
export class OrderService {
|
||||
private readonly logger = new Logger(OrderService.name);
|
||||
|
||||
constructor(
|
||||
private readonly em: EntityManager,
|
||||
private readonly orderRepository: OrderRepository,
|
||||
private readonly orderItemRepository: OrderItemRepository,
|
||||
private readonly paymentsService: PaymentsService,
|
||||
private readonly userService: UserService,
|
||||
private readonly productService: ProductService,
|
||||
private readonly productRepository: ProductRepository,
|
||||
private readonly ticketRepository: TicketRepository,
|
||||
private readonly ticketService: TicketService,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
) { }
|
||||
|
||||
async createOrder(userId: string, dto: CreateOrderDto) {
|
||||
const { attachments, content, items } = dto
|
||||
|
||||
const order = await this.em.transactional(async (em) => {
|
||||
const user = await this.userService.findById(userId)
|
||||
if (!user) {
|
||||
throw new BadRequestException("user not found")
|
||||
}
|
||||
const order = this.orderRepository.create({
|
||||
user,
|
||||
discount: 0,
|
||||
subTotal: 0,
|
||||
orderNumber: 1,
|
||||
total: 0,
|
||||
paidAmount: 0,
|
||||
balance: 0,
|
||||
status: OrderStatusEnum.NEW
|
||||
})
|
||||
|
||||
em.persist(order)
|
||||
|
||||
const productIds = items.map(item => item.productId)
|
||||
const products = await this.productRepository.find({
|
||||
id: { $in: productIds }
|
||||
})
|
||||
if (productIds.length !== products.length) {
|
||||
throw new BadRequestException("some products not found")
|
||||
}
|
||||
items.forEach(item => {
|
||||
const product = products.find(p => p.id == item.productId)
|
||||
if (!product) {
|
||||
throw new BadRequestException(`product ${product} not found`)
|
||||
}
|
||||
const orderItem = this.orderItemRepository.create({
|
||||
order,
|
||||
attributesValues: item.attributesValues,
|
||||
product,
|
||||
quantity: item.quantity,
|
||||
status: OrderItemStatus.PENDING,
|
||||
unitPrice: 0,
|
||||
totalPrice: 0,
|
||||
})
|
||||
em.persist(orderItem)
|
||||
});
|
||||
|
||||
const ticket = this.ticketRepository.create({
|
||||
content,
|
||||
user,
|
||||
attachments,
|
||||
status: TicketStatus.PENDING,
|
||||
admin: null
|
||||
})
|
||||
em.persist(ticket)
|
||||
|
||||
await em.flush()
|
||||
|
||||
return order
|
||||
})
|
||||
|
||||
return order
|
||||
}
|
||||
|
||||
async findAllForUser(userId: string, dto: FindOrdersDto) {
|
||||
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)
|
||||
|
||||
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 (let orderItem of targetOrder.items) {
|
||||
|
||||
const found = items.find(it => it.orderItemId == Number(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
|
||||
}
|
||||
|
||||
async confirmOrderItem(userId: string, orderId: string, orderItemId: number) {
|
||||
|
||||
const orderItem = await this.orderItemRepository.findOne({ id: orderItemId, order: { id: orderId } },
|
||||
{ populate: ['order', 'order.user'] })
|
||||
|
||||
if (!orderItem) {
|
||||
throw new BadRequestException("Order Item not found")
|
||||
}
|
||||
|
||||
if (orderItem.order.user.id !== userId) {
|
||||
throw new BadRequestException("Order Item does not belong to you")
|
||||
}
|
||||
|
||||
orderItem.status=OrderItemStatus.CONFIRMED
|
||||
|
||||
this.em.persistAndFlush(OrderItem)
|
||||
|
||||
return orderItem
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user