import { EventsHandler, IEventHandler } from '@nestjs/cqrs'; import { TransactionDataService } from 'src/modules/transaction/transaction/data/services/transaction-data.service'; import { TransactionChangeStatusEvent, TransactionCreateQueueEvent, } from 'src/modules/transaction/transaction/domain/entities/event/transaction-change-status.event'; import { TicketDataService } from '../../data/services/ticket.service'; import { QueueOrder } from '../../domain/entities/order.entity'; import { QueueTicket } from '../../domain/entities/ticket.entity'; import { QueueItem } from '../../domain/entities/queue-item.entity'; import * as moment from 'moment'; import { TransactionUserType } from 'src/modules/transaction/transaction/constants'; import { RegisterQueueManager } from '../../domain/usecases/register-queue.manager'; import { RegisterQueueDto } from '../controllers/dto/register-queue.dto'; import { QueueService } from '../../data/services/queue.service'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { QueueBucketReadService } from '../../data/services/queue-bucket'; import { QueueTimeFormula } from '../../domain/usecases/formula/queue-time.formula'; import { TransactionItemModel } from 'src/modules/transaction/transaction/data/models/transaction-item.model'; @EventsHandler(TransactionChangeStatusEvent, TransactionCreateQueueEvent) export class QueueTransactionHandler implements IEventHandler { constructor( private readonly dataService: TransactionDataService, private readonly ticketService: TicketDataService, private readonly queueService: QueueService, private readonly bucketService: QueueBucketReadService, private readonly queueTimeFormula: QueueTimeFormula, ) {} async handle(event: TransactionChangeStatusEvent) { const process_data = event.data.data; /** * If data still in process (not settled) then don't create the queue order */ if (process_data?.status != 'settled') return; const transaction = await this.dataService.getOneByOptions({ where: { id: event.data.id, }, relations: [ 'customer_category', 'items', 'items.item', 'items.item.bundling_items', ], }); const date = transaction.booking_date ?? transaction.invoice_date; const queue_date = moment(date, 'YYYY-MM-DD').unix(); const { id, customer_name, customer_phone, invoice_code } = transaction; const customerOrder = { code: invoice_code, customer: customer_name, phone: customer_phone, date: queue_date * 1000, transaction_id: id, }; const items = this.generateItems(transaction.items); const existTicket = await this.ticketService.ticketByUser( customer_name, customer_phone, ); const insertTickets: QueueTicket[] = []; if (customer_name && customer_phone && existTicket) { existTicket.items.push(...items); await this.ticketService.updateQueueTicket(existTicket); existTicket.items = items; insertTickets.push(existTicket); } else { const ticket: QueueTicket = { ...customerOrder, items }; const order: QueueOrder = { ...customerOrder, tickets: [ticket] }; const queueOrder = await this.ticketService.createQueueOrder(order); insertTickets.push(...queueOrder.tickets); } if ( transaction.customer_category?.has_vip_pass || transaction.customer_type === TransactionUserType.VIP ) { insertTickets.forEach((ticket) => { const ticket_id = ticket.id; const items = {}; ticket.items.forEach((item) => { const item_id = item['item_queue_id']; const currentItem = items[item_id]; if (currentItem) { currentItem.qty += item.qty; } items[item_id] = currentItem ? currentItem : { item_id, ticket_id, qty: item.qty, }; }); Object.values(items).forEach((payload: any) => { this.create(payload); }); }); } } generateItems(items: TransactionItemModel[]): QueueItem[] { const transactionItems = []; items.forEach((item) => { if (item.item.use_queue) { transactionItems.push({ item_queue_id: item.item.item_queue_id, item_id: item.item_id, qty: item.qty, }); } if (item.item.bundling_items.length > 0) { item.item.bundling_items.forEach((bundling_item) => { if (bundling_item.use_queue) { transactionItems.push({ item_queue_id: bundling_item.item_queue_id, item_id: bundling_item.id, qty: item.qty, }); } }); } }); return this.mergeQueueItems(transactionItems); } mergeQueueItems(arr) { const result = {}; arr.forEach((item) => { if (result[item.item_id]) { result[item.item_id].qty += item.qty; } else { result[item.item_id] = { ...item }; } }); return Object.values(result); } async create(data: RegisterQueueDto): Promise { const queue = await this.queueService.getTicketItems( data.ticket_id, data.item_id, ); const queueRequest: any = { qty: data.qty, item_id: queue.id, vip: true, }; const registerQueueManager = new RegisterQueueManager( this.bucketService, this.queueTimeFormula, ); registerQueueManager.setData(queueRequest); registerQueueManager.setService(this.queueService, TABLE_NAME.QUEUE); await registerQueueManager.execute(); } }