feat: split QR customer
parent
492a4ca2ba
commit
50e7f66bb7
|
@ -1,9 +1,13 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
|
||||
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
|
||||
import { Repository } from 'typeorm';
|
||||
import { QueueItemModel, QueueModel } from '../models/queue.model';
|
||||
import { DataSource, 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';
|
||||
|
||||
|
@ -25,6 +29,9 @@ export class QueueService extends BaseDataService<QueueModel> {
|
|||
|
||||
@InjectRepository(QueueItemModel, CONNECTION_NAME.DEFAULT)
|
||||
private item: Repository<QueueItemModel>,
|
||||
|
||||
@InjectDataSource(CONNECTION_NAME.DEFAULT)
|
||||
private dataSource: DataSource,
|
||||
) {
|
||||
super(repo);
|
||||
}
|
||||
|
@ -37,4 +44,19 @@ export class QueueService extends BaseDataService<QueueModel> {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
|||
import { BaseDataService } from 'src/core/modules/data/service/base-data.service';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
|
||||
import { Repository } from 'typeorm';
|
||||
import { In, Repository } from 'typeorm';
|
||||
import { QueueTicket } from '../../domain/entities/ticket.entity';
|
||||
import {
|
||||
QueueItemModel,
|
||||
|
@ -39,7 +39,50 @@ export class TicketDataService extends BaseDataService<QueueTicket> {
|
|||
});
|
||||
}
|
||||
|
||||
async orders(order_id: string): Promise<QueueOrderModel[]> {
|
||||
const order = await this.order.findOneOrFail({
|
||||
where: {
|
||||
id: order_id,
|
||||
},
|
||||
});
|
||||
|
||||
if (order.transaction_id != null) {
|
||||
return this.order.find({
|
||||
where: {
|
||||
code: order.code,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return [order];
|
||||
}
|
||||
|
||||
async orderIds(order_id: string): Promise<string[]> {
|
||||
const orders = await this.orders(order_id);
|
||||
|
||||
return orders.map((order) => order.id);
|
||||
}
|
||||
|
||||
async orderItems(
|
||||
order_id: string,
|
||||
item_ids: string[],
|
||||
): Promise<QueueOrderModel> {
|
||||
const order = await this.orderIds(order_id);
|
||||
return this.order.findOneOrFail({
|
||||
relations: ['tickets', 'tickets.items'],
|
||||
where: {
|
||||
tickets: {
|
||||
order_id: In(order),
|
||||
items: {
|
||||
id: In(item_ids),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async queueTickets(order_id: string): Promise<QueueTicketModel[]> {
|
||||
const order = await this.orderIds(order_id);
|
||||
return this.repo.find({
|
||||
relations: [
|
||||
'items',
|
||||
|
@ -48,7 +91,7 @@ export class TicketDataService extends BaseDataService<QueueTicket> {
|
|||
'items.item.item_queue',
|
||||
],
|
||||
where: {
|
||||
order_id,
|
||||
order_id: In(order),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -57,6 +100,7 @@ export class TicketDataService extends BaseDataService<QueueTicket> {
|
|||
order_id: string,
|
||||
ticket_id: string,
|
||||
): Promise<QueueTicketModel[]> {
|
||||
const order = await this.orderIds(order_id);
|
||||
return this.repo.find({
|
||||
relations: [
|
||||
'items',
|
||||
|
@ -65,7 +109,7 @@ export class TicketDataService extends BaseDataService<QueueTicket> {
|
|||
'items.item.item_queue',
|
||||
],
|
||||
where: {
|
||||
order_id,
|
||||
order_id: In(order),
|
||||
id: ticket_id,
|
||||
},
|
||||
});
|
||||
|
@ -75,6 +119,7 @@ export class TicketDataService extends BaseDataService<QueueTicket> {
|
|||
order_id: string,
|
||||
item_id: string,
|
||||
): Promise<QueueTicketModel[]> {
|
||||
const order = await this.orderIds(order_id);
|
||||
return this.repo.find({
|
||||
relations: [
|
||||
'items',
|
||||
|
@ -83,18 +128,19 @@ export class TicketDataService extends BaseDataService<QueueTicket> {
|
|||
'items.item.item_queue',
|
||||
],
|
||||
where: {
|
||||
order_id,
|
||||
order_id: In(order),
|
||||
items: [{ item_id }, { item: { item_queue: { id: item_id } } }],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async queueItems(order_id: string): Promise<QueueItemModel[]> {
|
||||
const order = await this.orderIds(order_id);
|
||||
return this.item.find({
|
||||
relations: ['queue', 'ticket'],
|
||||
where: {
|
||||
ticket: {
|
||||
order_id,
|
||||
order_id: In(order),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
export interface QueueBucket {
|
||||
id: string;
|
||||
queue_item_id: string;
|
||||
date: number;
|
||||
regular: number;
|
||||
vip: number;
|
||||
}
|
|
@ -2,7 +2,10 @@ import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|||
import { TicketDataService } from '../data/services/ticket.service';
|
||||
import { QueueOrder } from './entities/order.entity';
|
||||
import { Queue } from './entities/queue.entity';
|
||||
import { QueueService } from '../data/services/queue.service';
|
||||
import {
|
||||
QueueOrderService,
|
||||
QueueService,
|
||||
} from '../data/services/queue.service';
|
||||
import { RegisterQueueManager } from './usecases/register-queue.manager';
|
||||
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
|
||||
import { RegisterQueueDto } from '../infrastructure/controllers/dto/register-queue.dto';
|
||||
|
@ -11,13 +14,17 @@ import { CustomerQueueDetailManager } from './usecases/queue/customer-queue-deta
|
|||
import { CustomerQueueItemManager } from './usecases/queue/customer-queue-item.manager';
|
||||
import { CustomerQueueItemListManager } from './usecases/queue/customer-queue-item-list.manager';
|
||||
import { CustomerQueueListManager } from './usecases/queue/customer-queue-list.manager';
|
||||
import { SplitQueueDto } from '../infrastructure/controllers/dto/split-queue.dto';
|
||||
import { SplitQueueManager } from './usecases/split-queue.manager';
|
||||
|
||||
@Injectable()
|
||||
export class QueueOrchestrator {
|
||||
constructor(
|
||||
private readonly dataService: TicketDataService,
|
||||
private readonly queueService: QueueService,
|
||||
private readonly queueOrderService: QueueOrderService,
|
||||
private readonly registerQueueManager: RegisterQueueManager,
|
||||
private readonly splitQueueManager: SplitQueueManager,
|
||||
) {}
|
||||
|
||||
async loginCustomer(id: string): Promise<QueueOrder> {
|
||||
|
@ -46,6 +53,30 @@ export class QueueOrchestrator {
|
|||
return this.registerQueueManager.getResult();
|
||||
}
|
||||
|
||||
async split(data: SplitQueueDto): Promise<QueueOrder> {
|
||||
const queueIds = data.items.map((i) => i.queue_item_id);
|
||||
const queue = await this.dataService.orderItems(data.order_id, queueIds);
|
||||
// queue.tickets = queue.tickets.map((ticket) => {
|
||||
// ticket.items = ticket.items.map((item) => {
|
||||
// const itemQty = data.items.find((i) => i.queue_item_id === item.id);
|
||||
// return {
|
||||
// ...item,
|
||||
// qty: itemQty.qty,
|
||||
// };
|
||||
// });
|
||||
// return ticket;
|
||||
// });
|
||||
|
||||
this.splitQueueManager.setRequestData(data);
|
||||
this.splitQueueManager.setData(queue);
|
||||
this.splitQueueManager.setService(
|
||||
this.queueOrderService,
|
||||
TABLE_NAME.QUEUE_ORDER,
|
||||
);
|
||||
await this.splitQueueManager.execute();
|
||||
return this.splitQueueManager.getResult();
|
||||
}
|
||||
|
||||
async queueTickets(order_id: string): Promise<any> {
|
||||
const tickets = await this.dataService.queueTickets(order_id);
|
||||
const manager = new CustomerQueueSummaryManager(tickets);
|
||||
|
|
|
@ -19,6 +19,7 @@ export class CustomerQueueItemListManager extends CustomerQueueManager {
|
|||
const item_qty = items.reduce((acc, item) => acc + item.qty, 0);
|
||||
return {
|
||||
id: item.item_id,
|
||||
queue_item_id: item.id,
|
||||
title: item.item.item_queue?.name ?? item.item.name,
|
||||
image_url: item.item.image_url,
|
||||
qty: item_qty,
|
||||
|
|
|
@ -5,23 +5,41 @@ import {
|
|||
validateRelations,
|
||||
} from 'src/core/strings/constants/interface.constants';
|
||||
import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager';
|
||||
import { Queue } from '../entities/queue.entity';
|
||||
import { STATUS } from 'src/core/strings/constants/base.constants';
|
||||
import { QueueModel } from '../../data/models/queue.model';
|
||||
import { generateRandom } from 'src/modules/transaction/vip-code/domain/usecases/managers/helpers/generate-random.helper';
|
||||
import { QueueBucketReadService } from '../../data/services/queue-bucket';
|
||||
|
||||
@Injectable()
|
||||
export class RegisterQueueManager extends BaseCreateManager<QueueModel> {
|
||||
constructor(private readonly queueService: QueueBucketReadService) {
|
||||
super();
|
||||
}
|
||||
|
||||
async averageTime(): Promise<number> {
|
||||
const item = await this.getItem();
|
||||
return item.item.item.play_estimation;
|
||||
}
|
||||
|
||||
async beforeProcess(): Promise<void> {
|
||||
Object.assign(this.data, {
|
||||
status: STATUS.WAITING,
|
||||
time: new Date().getTime(),
|
||||
vip: false,
|
||||
code: `Q${generateRandom(4, true)}`,
|
||||
code: `A${generateRandom(4, true)}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
async getItem(): Promise<QueueModel> {
|
||||
return this.dataService.repo.findOne({
|
||||
relations: ['item', 'item.item'],
|
||||
where: {
|
||||
item_id: this.data.item_id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async afterProcess(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
EventTopics,
|
||||
columnUniques,
|
||||
validateRelations,
|
||||
} from 'src/core/strings/constants/interface.constants';
|
||||
import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager';
|
||||
|
||||
import { QueueOrderModel } from '../../data/models/queue.model';
|
||||
import { SplitQueueDto } from '../../infrastructure/controllers/dto/split-queue.dto';
|
||||
import { QueueService } from '../../data/services/queue.service';
|
||||
|
||||
@Injectable()
|
||||
export class SplitQueueManager extends BaseCreateManager<QueueOrderModel> {
|
||||
private dto: SplitQueueDto;
|
||||
constructor(private readonly queueService: QueueService) {
|
||||
super();
|
||||
}
|
||||
|
||||
setRequestData(dto: SplitQueueDto): void {
|
||||
this.dto = dto;
|
||||
}
|
||||
|
||||
prepareData(): Promise<void> {
|
||||
const { tickets, ...order } = this.data;
|
||||
const ticket = tickets[0];
|
||||
const items = tickets
|
||||
.map((ticket) => {
|
||||
return ticket.items;
|
||||
})
|
||||
.flat();
|
||||
this.data = {
|
||||
code: order.code,
|
||||
customer: order.customer,
|
||||
phone: order.phone,
|
||||
date: order.date,
|
||||
updated_at: new Date().getTime(),
|
||||
tickets: [
|
||||
{
|
||||
code: `${order.code}-1`,
|
||||
customer: this.dto.name,
|
||||
phone: this.dto.phone,
|
||||
date: ticket.date,
|
||||
order_id: order.id,
|
||||
items: items.map((item) => {
|
||||
const itemQty = this.dto.items.find(
|
||||
(i) => i.queue_item_id === item.id,
|
||||
);
|
||||
return {
|
||||
item_id: item.item_id,
|
||||
qty: itemQty.qty,
|
||||
};
|
||||
}),
|
||||
},
|
||||
],
|
||||
};
|
||||
super.prepareData();
|
||||
return;
|
||||
}
|
||||
|
||||
async beforeProcess(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
async afterProcess(): Promise<void> {
|
||||
this.dto.items.forEach((item) => {
|
||||
this.queueService.updateItemQty(item.queue_item_id, item.qty);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
get validateRelations(): validateRelations[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
get uniqueColumns(): columnUniques[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
get eventTopics(): EventTopics[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
get entityTarget(): any {
|
||||
return QueueOrderModel;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import {
|
||||
IsArray,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsString,
|
||||
Min,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
|
||||
export class ItemSplitQueueDto {
|
||||
@ApiProperty({ name: 'queue_item_id', required: true })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
queue_item_id: string;
|
||||
@ApiProperty({
|
||||
type: Number,
|
||||
required: true,
|
||||
example: 1,
|
||||
})
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
@IsNotEmpty()
|
||||
qty: number;
|
||||
}
|
||||
|
||||
export class SplitQueueDto {
|
||||
@ApiProperty({ name: 'order_id', required: true })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
order_id: string;
|
||||
|
||||
@ApiProperty({ name: 'name', required: true })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
name: string;
|
||||
|
||||
@ApiProperty({ name: 'phone', required: true })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
phone: string;
|
||||
|
||||
@ApiProperty({
|
||||
type: [ItemSplitQueueDto],
|
||||
required: false,
|
||||
example: [
|
||||
{
|
||||
queue_item_id: 'string',
|
||||
qty: 1,
|
||||
},
|
||||
],
|
||||
})
|
||||
@ValidateNested({ each: true })
|
||||
@IsArray()
|
||||
items: ItemSplitQueueDto[];
|
||||
}
|
|
@ -8,6 +8,7 @@ import { QueueOrchestrator } from '../../domain/queue.orchestrator';
|
|||
import { QueueOrder } from '../../domain/entities/order.entity';
|
||||
import { Queue } from '../../domain/entities/queue.entity';
|
||||
import { RegisterQueueDto } from './dto/register-queue.dto';
|
||||
import { SplitQueueDto } from './dto/split-queue.dto';
|
||||
|
||||
@ApiTags(`Queue`)
|
||||
@Controller(`v1/${MODULE_NAME.QUEUE}`)
|
||||
|
@ -21,6 +22,11 @@ export class QueueController {
|
|||
return await this.orchestrator.create(data);
|
||||
}
|
||||
|
||||
@Post('split')
|
||||
async splitQueue(@Body() data: SplitQueueDto): Promise<QueueOrder> {
|
||||
return await this.orchestrator.split(data);
|
||||
}
|
||||
|
||||
@Get('login/:id')
|
||||
async loginCustomer(@Param('id') id: string): Promise<QueueOrder> {
|
||||
return await this.orchestrator.loginCustomer(id);
|
||||
|
|
Loading…
Reference in New Issue