feat: add queue admin list
continuous-integration/drone/push Build is passing Details

pull/115/head
shancheas 2024-10-25 14:49:56 +07:00
parent 143bf76417
commit 5b507a1c3c
16 changed files with 306 additions and 2 deletions

View File

@ -88,6 +88,7 @@ import {
QueueOrderModel, QueueOrderModel,
QueueTicketModel, QueueTicketModel,
QueueItemModel, QueueItemModel,
QueueModel,
} from './modules/queue/data/models/queue.model'; } from './modules/queue/data/models/queue.model';
import { ItemQueueModule } from './modules/item-related/item-queue/item-queue.module'; import { ItemQueueModule } from './modules/item-related/item-queue/item-queue.module';
import { ItemQueueModel } from './modules/item-related/item-queue/data/models/item-queue.model'; import { ItemQueueModel } from './modules/item-related/item-queue/data/models/item-queue.model';
@ -149,6 +150,7 @@ import { ItemQueueModel } from './modules/item-related/item-queue/data/models/it
QueueOrderModel, QueueOrderModel,
QueueTicketModel, QueueTicketModel,
QueueItemModel, QueueItemModel,
QueueModel,
], ],
synchronize: false, synchronize: false,
}), }),

View File

@ -37,6 +37,7 @@ export enum TABLE_NAME {
REPORT_BOOKMARK = 'report_bookmark', REPORT_BOOKMARK = 'report_bookmark',
EXPORT_REPORT_HISTORY = 'export_report_history', EXPORT_REPORT_HISTORY = 'export_report_history',
QUEUE = 'queues',
QUEUE_ORDER = 'queue_orders', QUEUE_ORDER = 'queue_orders',
QUEUE_TICKET = 'queue_tickets', QUEUE_TICKET = 'queue_tickets',
QUEUE_ITEM = 'queue_items', QUEUE_ITEM = 'queue_items',

View File

@ -0,0 +1,22 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddQueueTable1729756969674 implements MigrationInterface {
name = 'AddQueueTable1729756969674';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "queues" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "code" character varying NOT NULL, "status" character varying NOT NULL, "time" bigint NOT NULL, "call_time" bigint NOT NULL, "vip" boolean NOT NULL, "item_id" uuid NOT NULL, "qty" integer NOT NULL, CONSTRAINT "PK_d966f9eb39a9396658387071bb3" PRIMARY KEY ("id"))`,
);
await queryRunner.query(
`ALTER TABLE "queues" ADD CONSTRAINT "FK_435954e9a0d9967f17e043d54b4" FOREIGN KEY ("item_id") REFERENCES "queue_items"("id") ON DELETE CASCADE ON UPDATE CASCADE`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "queues" DROP CONSTRAINT "FK_435954e9a0d9967f17e043d54b4"`,
);
await queryRunner.query(`DROP TABLE "queues"`);
}
}

View File

@ -0,0 +1,39 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class AddQueueBaseModel1729838994129 implements MigrationInterface {
name = 'AddQueueBaseModel1729838994129';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "queues" ADD "creator_id" character varying(36)`,
);
await queryRunner.query(
`ALTER TABLE "queues" ADD "creator_name" character varying(125)`,
);
await queryRunner.query(
`ALTER TABLE "queues" ADD "editor_id" character varying(36)`,
);
await queryRunner.query(
`ALTER TABLE "queues" ADD "editor_name" character varying(125)`,
);
await queryRunner.query(
`ALTER TABLE "queues" ADD "created_at" bigint NOT NULL`,
);
await queryRunner.query(
`ALTER TABLE "queues" ADD "updated_at" bigint NOT NULL`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "queues" ALTER COLUMN "call_time" DROP NOT NULL`,
);
await queryRunner.query(`ALTER TABLE "queues" DROP COLUMN "updated_at"`);
await queryRunner.query(`ALTER TABLE "queues" DROP COLUMN "created_at"`);
await queryRunner.query(`ALTER TABLE "queues" DROP COLUMN "editor_name"`);
await queryRunner.query(`ALTER TABLE "queues" DROP COLUMN "editor_id"`);
await queryRunner.query(`ALTER TABLE "queues" DROP COLUMN "creator_name"`);
await queryRunner.query(`ALTER TABLE "queues" DROP COLUMN "creator_id"`);
}
}

View File

@ -14,4 +14,8 @@ export class ItemQueueReadService extends BaseReadService<ItemQueueEntity> {
) { ) {
super(repo); super(repo);
} }
async list(): Promise<ItemQueueEntity[]> {
return this.repo.find();
}
} }

View File

@ -24,6 +24,11 @@ export class ItemQueueReadOrchestrator extends BaseReadOrchestrator<ItemQueueEnt
return this.indexManager.getResult(); return this.indexManager.getResult();
} }
async list(): Promise<ItemQueueEntity[]> {
const items = await this.serviceData.list();
return items;
}
async detail(dataId: string): Promise<ItemQueueEntity> { async detail(dataId: string): Promise<ItemQueueEntity> {
this.detailManager.setData(dataId); this.detailManager.setData(dataId);
this.detailManager.setService(this.serviceData, TABLE_NAME.ITEM_QUEUE); this.detailManager.setService(this.serviceData, TABLE_NAME.ITEM_QUEUE);

View File

@ -23,6 +23,19 @@ export class ItemQueueReadController {
return await this.orchestrator.index(params); return await this.orchestrator.index(params);
} }
@Get('list')
@Public(true)
async list() {
const list = await this.orchestrator.list();
return list.map(({ id, name, item_type }) => {
return {
id,
name,
item_type,
};
});
}
@Get(':id') @Get(':id')
async detail(@Param('id') id: string): Promise<ItemQueueEntity> { async detail(@Param('id') id: string): Promise<ItemQueueEntity> {
return await this.orchestrator.detail(id); return await this.orchestrator.detail(id);

View File

@ -4,9 +4,10 @@ import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { QueueTicket } from '../../domain/entities/ticket.entity'; import { QueueTicket } from '../../domain/entities/ticket.entity';
import { QueueItem } from '../../domain/entities/queue-item.entity'; import { QueueItem } from '../../domain/entities/queue-item.entity';
import { ItemEntity } from 'src/modules/item-related/item/domain/entities/item.entity';
import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; import { ItemModel } from 'src/modules/item-related/item/data/models/item.model';
import { Queue } from '../../domain/entities/queue.entity';
import { BaseModel } from 'src/core/modules/data/model/base.model';
@Entity(TABLE_NAME.QUEUE_ORDER) @Entity(TABLE_NAME.QUEUE_ORDER)
export class QueueOrderModel export class QueueOrderModel
@ -83,6 +84,12 @@ export class QueueItemModel
@JoinColumn({ name: 'ticket_id' }) @JoinColumn({ name: 'ticket_id' })
ticket: QueueTicket; ticket: QueueTicket;
@OneToMany(() => QueueModel, (model) => model.item, {
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
queue: QueueModel[];
@Column('varchar') @Column('varchar')
item_id: string; item_id: string;
@ -93,3 +100,34 @@ export class QueueItemModel
@Column('int') @Column('int')
qty: number; qty: number;
} }
@Entity(TABLE_NAME.QUEUE)
export class QueueModel extends BaseModel<Queue> implements Queue {
@Column('varchar')
code: string;
@Column('varchar')
status: string;
@Column({ type: 'bigint' })
time: number;
@Column({ type: 'bigint' })
call_time: number;
@Column({ type: 'boolean' })
vip: boolean;
@ManyToOne(() => QueueItemModel, (model) => model.queue, {
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
@JoinColumn({ name: 'item_id' })
item: QueueItemModel;
@Column('varchar')
item_id: string;
@Column('int')
qty: number;
}

View File

@ -0,0 +1,17 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
import { Repository } from 'typeorm';
import { QueueModel } from '../models/queue.model';
import { BaseReadService } from 'src/core/modules/data/service/base-read.service';
@Injectable()
export class QueueDataService extends BaseReadService<QueueModel> {
constructor(
@InjectRepository(QueueModel, CONNECTION_NAME.DEFAULT)
private repo: Repository<QueueModel>,
) {
super(repo);
}
}

View File

@ -0,0 +1,4 @@
export interface FilterQueueEntity {
vip: boolean;
status: string[];
}

View File

@ -0,0 +1,12 @@
import { BaseCoreEntity } from 'src/core/modules/domain/entities/base-core.entity';
import { QueueItem } from './queue-item.entity';
export interface Queue extends BaseCoreEntity {
code: string;
qty: number;
status: string;
time: number;
vip: boolean;
call_time: number;
item: QueueItem;
}

View File

@ -0,0 +1,21 @@
import { Injectable } from '@nestjs/common';
import { QueueDataService } from '../data/services/queue.service';
import { IndexQueueManager } from './usecases/index-queue.manager';
import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
import { Queue } from './entities/queue.entity';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
@Injectable()
export class QueueAdminOrchestrator {
constructor(
private readonly dataService: QueueDataService,
private indexManager: IndexQueueManager,
) {}
async index(params): Promise<PaginationResponse<Queue>> {
this.indexManager.setFilterParam(params);
this.indexManager.setService(this.dataService, TABLE_NAME.QUEUE);
await this.indexManager.execute();
return this.indexManager.getResult();
}
}

View File

@ -0,0 +1,69 @@
import { Injectable } from '@nestjs/common';
import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager';
import { SelectQueryBuilder } from 'typeorm';
import {
Param,
RelationParam,
} from 'src/core/modules/domain/entities/base-filter.entity';
import { Queue } from '../entities/queue.entity';
@Injectable()
export class IndexQueueManager extends BaseIndexManager<Queue> {
async prepareData(): Promise<void> {
return;
}
async beforeProcess(): Promise<void> {
return;
}
async afterProcess(): Promise<void> {
return;
}
get relations(): RelationParam {
return {
joinRelations: [],
selectRelations: ['item', 'item.ticket'],
countRelations: [],
};
}
get selects(): string[] {
return [
`${this.tableName}.id`,
`${this.tableName}.code`,
`${this.tableName}.status`,
`${this.tableName}.time`,
`${this.tableName}.call_time`,
`${this.tableName}.vip`,
`${this.tableName}.item`,
`${this.tableName}.qty`,
`${this.tableName}.created_at`,
`item.id`,
`ticket.customer`,
`ticket.phone`,
];
}
get specificFilter(): Param[] {
return [
{
cols: `${this.tableName}.status`,
data: this.filterParam.status,
},
];
}
setQueryFilter(
queryBuilder: SelectQueryBuilder<Queue>,
): SelectQueryBuilder<Queue> {
if (this.filterParam.vip != null) {
queryBuilder.andWhere(`${this.tableName}.vip = :vip`, {
vip: this.filterParam.vip,
});
}
return queryBuilder;
}
}

View File

@ -0,0 +1,24 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsBoolean, ValidateIf } from 'class-validator';
import { Transform } from 'class-transformer';
import { FilterQueueEntity } from 'src/modules/queue/domain/entities/filter.entity';
export class QueueDto implements FilterQueueEntity {
@ApiProperty({
isArray: true,
required: false,
})
// @IsString()
@ValidateIf((body) => body.status)
@Transform(({ value }) => {
if (!value) return [];
return Array.isArray(value) ? value : [value];
})
status: string[];
@ApiProperty({ type: Boolean, required: false })
@Transform((body) => body.value == 'true')
@IsBoolean()
@ValidateIf((body) => body.vip)
vip: boolean;
}

View File

@ -0,0 +1,23 @@
import { Controller, Get, Query } from '@nestjs/common';
import { MODULE_NAME } from 'src/core/strings/constants/module.constants';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { Public } from 'src/core/guards';
import { QueueAdminOrchestrator } from '../../domain/queue-admin.orchestrator';
import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
import { Queue } from '../../domain/entities/queue.entity';
import { QueueDto } from './dto/queue.filter';
@ApiTags(`Queue Admin`)
@Controller(`v1/${MODULE_NAME.QUEUE}-admin`)
@Public(true)
@ApiBearerAuth('JWT')
export class QueueAdminController {
constructor(private orchestrator: QueueAdminOrchestrator) {}
@Get('queues')
async index(@Query() params: QueueDto): Promise<PaginationResponse<Queue>> {
return await this.orchestrator.index(params);
}
}

View File

@ -8,6 +8,7 @@ import { CqrsModule } from '@nestjs/cqrs';
import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; import { ItemModel } from 'src/modules/item-related/item/data/models/item.model';
import { import {
QueueItemModel, QueueItemModel,
QueueModel,
QueueOrderModel, QueueOrderModel,
QueueTicketModel, QueueTicketModel,
} from './data/models/queue.model'; } from './data/models/queue.model';
@ -17,6 +18,10 @@ import { QueueTransactionHandler } from './infrastructure/handlers/transaction.h
import { TransactionDataService } from '../transaction/transaction/data/services/transaction-data.service'; import { TransactionDataService } from '../transaction/transaction/data/services/transaction-data.service';
import { TransactionModel } from '../transaction/transaction/data/models/transaction.model'; import { TransactionModel } from '../transaction/transaction/data/models/transaction.model';
import { TicketDataService } from './data/services/ticket.service'; import { TicketDataService } from './data/services/ticket.service';
import { QueueDataService } from './data/services/queue.service';
import { QueueAdminController } from './infrastructure/controllers/queue-admin.controller';
import { QueueAdminOrchestrator } from './domain/queue-admin.orchestrator';
import { IndexQueueManager } from './domain/usecases/index-queue.manager';
@Module({ @Module({
imports: [ imports: [
@ -26,6 +31,7 @@ import { TicketDataService } from './data/services/ticket.service';
QueueOrderModel, QueueOrderModel,
QueueTicketModel, QueueTicketModel,
QueueItemModel, QueueItemModel,
QueueModel,
ItemModel, ItemModel,
TransactionModel, TransactionModel,
], ],
@ -33,14 +39,18 @@ import { TicketDataService } from './data/services/ticket.service';
), ),
CqrsModule, CqrsModule,
], ],
controllers: [QueueController], controllers: [QueueController, QueueAdminController],
providers: [ providers: [
QueueTransactionHandler, QueueTransactionHandler,
QueueOrchestrator, QueueOrchestrator,
QueueAdminOrchestrator,
TransactionDataService, TransactionDataService,
TicketDataService, TicketDataService,
QueueDataService,
IndexQueueManager,
], ],
}) })
export class QueueModule {} export class QueueModule {}