pos-be/src/modules/queue/data/services/queue.service.ts

229 lines
5.9 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { Between, DataSource, In, Not, Repository } from 'typeorm';
import {
QueueItemModel,
QueueModel,
QueueOrderModel,
} from '../models/queue.model';
import { BaseReadService } from 'src/core/modules/data/service/base-read.service';
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<QueueModel> {
constructor(
@InjectRepository(QueueModel, CONNECTION_NAME.DEFAULT)
private repo: Repository<QueueModel>,
@InjectRepository(ItemQueueModel, CONNECTION_NAME.DEFAULT)
private itemQueueRepo: Repository<ItemQueueModel>,
) {
super(repo);
}
async waitingQueue(item_queue_id: string) {
const start = moment().startOf('day').valueOf();
const end = moment().endOf('day').valueOf();
return this.repo.find({
where: {
time: Between(start, end),
item_queue_id,
status: 'waiting',
},
order: {
time: 'ASC',
},
});
}
async doneQueue(item_queue_id: string) {
const start = moment().startOf('day').valueOf();
const end = moment().endOf('day').valueOf();
return this.repo.find({
where: {
time: Between(start, end),
item_queue_id,
status: In(['done', 'called']),
},
order: {
time: 'ASC',
},
});
}
async exclude(item_queue_id: string[]) {
const queues = await this.itemQueueRepo.find({
relations: ['items'],
where: {
id: Not(In(item_queue_id)),
},
});
return queues.filter((q) => q.items.length > 0);
}
async lastQueue(item_queue_id: string) {
const start = moment().startOf('day').valueOf();
const end = moment().endOf('day').valueOf();
return this.repo.findOne({
where: {
time: Between(start, end),
item_queue_id,
status: 'called',
},
order: {
call_time: 'DESC',
},
});
}
/**
* @deprecated
* Change to QueueTimeFormula (queue-time.formula.ts)
* @param item_queue_id
* @returns
*/
async queueTimes(item_queue_id: string): Promise<any> {
const queueTimes = {};
let now = moment().valueOf();
const itemQueue = await this.itemQueueRepo.findOne({
relations: ['items'],
where: {
id: item_queue_id,
},
});
const times = itemQueue.items.map((item) => item.play_estimation ?? 0);
const average = math.mean(times) * 60 * 1000; // change average minute to milliseconds
const queues = await this.repo.find({
where: {
item_queue_id,
status: 'waiting',
},
});
queueTimes[queues[0].id] = now; // first queue will be now
for (let i = 1; i < queues.length; i++) {
const queue = queues[i];
// duration will be total qty multiple by average
const duration = queue.qty * average;
// time to call will be now + duration
const time = now + duration;
queueTimes[queue.id] = time;
// update now to last call time
now = time;
}
return queueTimes;
}
async queueItems(item_queue_id: string[]): Promise<QueueModel[]> {
return this.repo.find({
relations: ['item', 'item.item', 'item.item.item_queue'],
where: {
item: { item: { item_queue: { id: In(item_queue_id) } } },
},
order: {
time: 'DESC',
},
});
}
}
@Injectable()
export class QueueService extends BaseDataService<QueueModel> {
constructor(
@InjectRepository(QueueModel, CONNECTION_NAME.DEFAULT)
private repo: Repository<QueueModel>,
@InjectRepository(QueueItemModel, CONNECTION_NAME.DEFAULT)
private item: Repository<QueueItemModel>,
@InjectRepository(ItemModel, CONNECTION_NAME.DEFAULT)
private itemMaster: Repository<ItemModel>,
@InjectDataSource(CONNECTION_NAME.DEFAULT)
private dataSource: DataSource,
) {
super(repo);
}
async queues(ids: string[]) {
const start = moment().startOf('day').valueOf();
const end = moment().endOf('day').valueOf();
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),
},
order: {
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 = times.length > 0 ? math.mean(times) * 60 * 1000 : 0; // change average minute to milliseconds
return average;
}
async getTicketItems(ticket_id: string, item_id: string) {
return this.item.findOneOrFail({
relations: ['item'],
where: [
{
ticket_id,
item_id,
},
{
ticket_id,
item: { item_queue_id: item_id },
},
],
});
}
async updateItemQty(item_id: string, qty: number): Promise<void> {
const query = `UPDATE queue_items SET qty = qty - ${qty} WHERE id = '${item_id}'`;
this.dataSource.query(query);
}
}
@Injectable()
export class QueueOrderService extends BaseDataService<QueueOrderModel> {
constructor(
@InjectRepository(QueueOrderModel, CONNECTION_NAME.DEFAULT)
private repo: Repository<QueueOrderModel>,
) {
super(repo);
}
}