diff --git a/src/modules/queue/data/models/queue.model.ts b/src/modules/queue/data/models/queue.model.ts index ec2083f..57c2b2f 100644 --- a/src/modules/queue/data/models/queue.model.ts +++ b/src/modules/queue/data/models/queue.model.ts @@ -136,4 +136,6 @@ export class QueueModel extends BaseModel implements Queue { @Column('int') qty: number; + + average = 0; } diff --git a/src/modules/queue/data/services/queue-bucket.ts b/src/modules/queue/data/services/queue-bucket.ts index 0042c4a..4e5bacb 100644 --- a/src/modules/queue/data/services/queue-bucket.ts +++ b/src/modules/queue/data/services/queue-bucket.ts @@ -24,16 +24,9 @@ export class QueueBucketReadService extends BaseReadService { const start = moment().startOf('day').valueOf(); const end = moment().endOf('day').valueOf(); - const queueItem = await this.item.findOne({ - relations: ['item'], - where: { - id: item_id, - }, - }); - const queue = await this.repo.findOne({ where: { - queue_item_id: queueItem.item.item_queue_id ?? queueItem.item.id, + queue_item_id: item_id, date: Between(start, end), }, }); @@ -42,7 +35,7 @@ export class QueueBucketReadService extends BaseReadService { const regularNumber = vip ? 0 : 1; const vipNumber = vip ? 1 : 0; await this.repo.save({ - queue_item_id: queueItem.item.item_queue_id ?? queueItem.item.id, + queue_item_id: item_id, date: start, regular: regularNumber, vip: vipNumber, diff --git a/src/modules/queue/data/services/queue.service.ts b/src/modules/queue/data/services/queue.service.ts index e41ba60..4f7ab15 100644 --- a/src/modules/queue/data/services/queue.service.ts +++ b/src/modules/queue/data/services/queue.service.ts @@ -13,6 +13,7 @@ import { BaseDataService } from 'src/core/modules/data/service/base-data.service import { ItemQueueModel } from 'src/modules/item-related/item-queue/data/models/item-queue.model'; import * as moment from 'moment'; import * as math from 'mathjs'; +import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; @Injectable() export class QueueDataService extends BaseReadService { @@ -136,6 +137,9 @@ export class QueueService extends BaseDataService { @InjectRepository(QueueItemModel, CONNECTION_NAME.DEFAULT) private item: Repository, + @InjectRepository(ItemModel, CONNECTION_NAME.DEFAULT) + private itemMaster: Repository, + @InjectDataSource(CONNECTION_NAME.DEFAULT) private dataSource: DataSource, ) { @@ -145,7 +149,13 @@ export class QueueService extends BaseDataService { async queues(ids: string[]) { const start = moment().startOf('day').valueOf(); const end = moment().endOf('day').valueOf(); - return this.repo.find({ + const playEstimations = {}; + + for (const id of ids) { + playEstimations[id] = await this.itemAverageTimeEstimation(id); + } + + const queues = await this.repo.find({ where: { item_queue_id: In(ids), time: Between(start, end), @@ -154,6 +164,24 @@ export class QueueService extends BaseDataService { time: 'ASC', }, }); + + queues.forEach((queue) => { + queue.average = playEstimations[queue.item_queue_id]; + }); + + return queues; + } + + async itemAverageTimeEstimation(item_queue_id: string) { + const items = await this.itemMaster.find({ + where: { + item_queue_id, + }, + }); + + const times = items.map((item) => item.play_estimation ?? 0); + const average = math.mean(times) * 60 * 1000; // change average minute to milliseconds + return average; } async getTicketItems(ticket_id: string, item_id: string) { diff --git a/src/modules/queue/domain/usecases/formula/queue-condition.formula.ts b/src/modules/queue/domain/usecases/formula/queue-condition.formula.ts index 05f9d28..ce3d387 100644 --- a/src/modules/queue/domain/usecases/formula/queue-condition.formula.ts +++ b/src/modules/queue/domain/usecases/formula/queue-condition.formula.ts @@ -1,6 +1,8 @@ import { QueueModel } from 'src/modules/queue/data/models/queue.model'; import { toTime } from '../../helpers/time.helper'; import * as math from 'mathjs'; +import { QueueTimeFormula } from './queue-time.formula'; +import * as moment from 'moment'; export class QueueCondition { private ticketItems = {}; @@ -14,23 +16,59 @@ export class QueueCondition { condition(item_id: string) { const queues: QueueModel[] = this.ticketItems[item_id] ?? []; - const time = queues[0]; - const nearest = time ? toTime(time.time) : 0; + const playEstimation = queues[0]?.average ?? 0; + const [time, last] = this.queueTime(queues, playEstimation); + const nearest = time ? toTime(time) : 0; + const lastTime = last ? toTime(last + playEstimation) : 0; + + const queuePeople = this.queuePeople(queues); - const last = [...queues].pop(); - const lastTime = last ? toTime(last.time) : 0; return { - available: queues.length == 0, + available: queuePeople == 0, average: this.averageTime(queues), nearest: nearest, - crowded_level: queues.length, + crowded_level: queuePeople, available_time: lastTime, }; } + queuePeople(queues: QueueModel[]): number { + const queue = this.activeQueue(queues); + const queuePeople = queue.reduce((acc, q) => { + return acc + q.qty; + }, 0); + return queuePeople; + } + + activeQueue(queues: QueueModel[]) { + return queues.filter((q) => q.status == 'waiting'); + } + + queueTime(queues: QueueModel[], average = 0): number[] { + const calledQueue = queues.filter((q) => + ['called', 'done'].includes(q.status), + ); + const lastCalledQueue = calledQueue[calledQueue.length - 1]; + const activeQueues = this.activeQueue(queues); + + const queueTimes = QueueTimeFormula.queueTime( + activeQueues, + lastCalledQueue, + average, + ); + + const queueEstimation = Object.values(queueTimes); + + const first = queueEstimation[0] ?? moment().valueOf(); + const last = queueEstimation[queueEstimation.length - 1] ?? 0; + return [first, last]; + } + averageTime(queues: QueueModel[]) { if (queues.length == 0) return 0; - const calledQueue = queues.filter((q) => q.status === 'called'); + const calledQueue = queues.filter((q) => + ['called', 'done'].includes(q.status), + ); if (calledQueue.length < 1) return 0; diff --git a/src/modules/queue/domain/usecases/formula/queue-time.formula.ts b/src/modules/queue/domain/usecases/formula/queue-time.formula.ts index a56dd40..20e1e95 100644 --- a/src/modules/queue/domain/usecases/formula/queue-time.formula.ts +++ b/src/modules/queue/domain/usecases/formula/queue-time.formula.ts @@ -5,6 +5,7 @@ import { QueueDataService } from 'src/modules/queue/data/services/queue.service' import { Repository } from 'typeorm'; import * as moment from 'moment'; import * as math from 'mathjs'; +import { QueueModel } from 'src/modules/queue/data/models/queue.model'; export class QueueTimeFormula { constructor( @@ -31,9 +32,18 @@ export class QueueTimeFormula { const calledQueue = await this.queueDataService.lastQueue(item_queue_id); + return QueueTimeFormula.queueTime(queues, calledQueue, average); + } + + static queueTime( + queues: QueueModel[], + lastQueue: QueueModel, + average: number, + ) { const queueTimes = {}; + if (queues.length < 1) return queueTimes; const timeNow = moment().valueOf(); - const lastCall = calledQueue?.call_time ?? timeNow - average; + const lastCall = lastQueue?.call_time ?? timeNow - average; const callTime = +lastCall + average; const currentQueueCallTime = timeNow > callTime ? timeNow : callTime; diff --git a/src/modules/queue/domain/usecases/queue/customer-queue.manager.ts b/src/modules/queue/domain/usecases/queue/customer-queue.manager.ts index 915e850..8c5ab2b 100644 --- a/src/modules/queue/domain/usecases/queue/customer-queue.manager.ts +++ b/src/modules/queue/domain/usecases/queue/customer-queue.manager.ts @@ -106,7 +106,7 @@ export class CustomerQueueManager { const queueItem = item.item.item_queue ?? item.item; return { id: item.item_id, - queue_item_id: item.id, + queue_item_id: queueItem.id, title: queueItem.name, image_url: item.item.image_url, qty: item_qty, diff --git a/src/modules/queue/domain/usecases/register-queue.manager.ts b/src/modules/queue/domain/usecases/register-queue.manager.ts index 10176bd..3b5679b 100644 --- a/src/modules/queue/domain/usecases/register-queue.manager.ts +++ b/src/modules/queue/domain/usecases/register-queue.manager.ts @@ -10,10 +10,14 @@ import { QueueItemModel, QueueModel } from '../../data/models/queue.model'; import { padCode } from 'src/modules/transaction/vip-code/domain/usecases/managers/helpers/generate-random.helper'; import { QueueBucketReadService } from '../../data/services/queue-bucket'; import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; +import { QueueTimeFormula } from './formula/queue-time.formula'; @Injectable() export class RegisterQueueManager extends BaseCreateManager { - constructor(private readonly bucketService: QueueBucketReadService) { + constructor( + private readonly bucketService: QueueBucketReadService, + private readonly queueTimeFormula: QueueTimeFormula, + ) { super(); } @@ -22,11 +26,22 @@ export class RegisterQueueManager extends BaseCreateManager { return item.play_estimation; } + async queueTime(queue_id: string): Promise { + const queueTimes = await this.queueTimeFormula.items(queue_id); + const queues = Object.values(queueTimes); + + const first = queues[0]; + const last = queues[queues.length - 1]; + return [first, last]; + } + async beforeProcess(): Promise { const vip = this.data.vip ?? false; const item = await this.getItemMaster(); + const [, end] = await this.queueTime(item.item_queue_id); + const queueNumber = await this.bucketService.getQueue( - this.data.item_id, + item.item_queue_id, vip, ); const prefix = vip ? 'B' : 'A'; @@ -34,7 +49,7 @@ export class RegisterQueueManager extends BaseCreateManager { Object.assign(this.data, { status: STATUS.WAITING, - time: new Date().getTime(), + time: end, item_queue_id: item.item_queue_id, vip, code, diff --git a/src/modules/queue/infrastructure/handlers/transaction.handler.ts b/src/modules/queue/infrastructure/handlers/transaction.handler.ts index 57d42ca..d6413e9 100644 --- a/src/modules/queue/infrastructure/handlers/transaction.handler.ts +++ b/src/modules/queue/infrastructure/handlers/transaction.handler.ts @@ -15,6 +15,7 @@ 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'; @EventsHandler(TransactionChangeStatusEvent, TransactionCreateQueueEvent) export class QueueTransactionHandler @@ -25,6 +26,7 @@ export class QueueTransactionHandler private readonly ticketService: TicketDataService, private readonly queueService: QueueService, private readonly bucketService: QueueBucketReadService, + private readonly queueTimeFormula: QueueTimeFormula, ) {} async handle(event: TransactionChangeStatusEvent) { @@ -125,7 +127,10 @@ export class QueueTransactionHandler item_id: queue.id, vip: true, }; - const registerQueueManager = new RegisterQueueManager(this.bucketService); + const registerQueueManager = new RegisterQueueManager( + this.bucketService, + this.queueTimeFormula, + ); registerQueueManager.setData(queueRequest); registerQueueManager.setService(this.queueService, TABLE_NAME.QUEUE); await registerQueueManager.execute();