From 3e676226b1570124dbe3d5a73f4614e8a99b9409 Mon Sep 17 00:00:00 2001 From: shancheas Date: Fri, 7 Feb 2025 16:25:29 +0700 Subject: [PATCH] feat: create ticket gate scan --- .../gates/infrastructure/dto/logs.dto.ts | 1 - .../gates/infrastructure/gate.controller.ts | 4 +- src/modules/queue/data/models/queue.model.ts | 3 + .../queue/data/services/ticket.service.ts | 24 ++++- .../queue/domain/entities/ticket.entity.ts | 1 + .../queue/domain/queue.orchestrator.ts | 10 ++ .../usecases/generate-transaction.manager.ts | 91 +++++++++++++++++++ .../queue/customer-queue-summary.manager.ts | 1 + .../controllers/queue.controller.ts | 48 +++++++++- src/modules/queue/queue.module.ts | 2 + 10 files changed, 177 insertions(+), 8 deletions(-) create mode 100644 src/modules/queue/domain/usecases/generate-transaction.manager.ts diff --git a/src/modules/gates/infrastructure/dto/logs.dto.ts b/src/modules/gates/infrastructure/dto/logs.dto.ts index 011e757..ee138c0 100644 --- a/src/modules/gates/infrastructure/dto/logs.dto.ts +++ b/src/modules/gates/infrastructure/dto/logs.dto.ts @@ -8,7 +8,6 @@ export class GateLogDto implements GateLogEntity { required: true, }) @IsNotEmpty() - @IsString() gate_id: string; @ApiProperty({ diff --git a/src/modules/gates/infrastructure/gate.controller.ts b/src/modules/gates/infrastructure/gate.controller.ts index 4da847b..7cc7a71 100644 --- a/src/modules/gates/infrastructure/gate.controller.ts +++ b/src/modules/gates/infrastructure/gate.controller.ts @@ -7,7 +7,6 @@ import { GateMasterEntity, GateResponseEntity, } from '../domain/entity/gate-response.entity'; -import { Gate } from 'src/core/response'; import { GateLogDto } from './dto/logs.dto'; const masterGates = [ @@ -49,7 +48,6 @@ const gateResponses = [ @ApiTags(`Gate - read`) @Controller(`v1/gate`) @Public(true) -@Gate() export class GateController { @Post('scan') async scan( @@ -77,7 +75,7 @@ export class GateController { async logs(@Body() data: GateLogDto): Promise { console.log(data); - return { code: 1, message: 'success' }; + return { code: 0, message: 'Berhasil menyimpan logs' }; } @Get(':id/master') diff --git a/src/modules/queue/data/models/queue.model.ts b/src/modules/queue/data/models/queue.model.ts index dd3ec16..39045a0 100644 --- a/src/modules/queue/data/models/queue.model.ts +++ b/src/modules/queue/data/models/queue.model.ts @@ -64,6 +64,9 @@ export class QueueTicketModel @Column({ type: 'bigint' }) date: number; + @Column({ type: 'boolean' }) + is_printed?: boolean; + @OneToMany(() => QueueItemModel, (model) => model.ticket, { cascade: true, onDelete: 'CASCADE', diff --git a/src/modules/queue/data/services/ticket.service.ts b/src/modules/queue/data/services/ticket.service.ts index 24827e4..15f5506 100644 --- a/src/modules/queue/data/services/ticket.service.ts +++ b/src/modules/queue/data/services/ticket.service.ts @@ -81,12 +81,34 @@ export class TicketDataService extends BaseDataService { }); } + async printTicket(id: string): Promise { + const tickets = await this.repo.find({ + where: { + order_id: id, + is_printed: false, + }, + }); + + await this.repo.update( + { order_id: id, is_printed: false }, + { is_printed: true }, + ); + + if (tickets.length < 1) + throw new UnprocessableEntityException({ + code: 2, + message: 'Semua ticket sudah di print', + }); + + return tickets; + } + async ticketByUser(user: string, phone: string): Promise { const start = moment().startOf('day').valueOf(); const end = moment().endOf('day').valueOf(); return this.repo.findOne({ - relations: ['items'], + relations: ['items', 'order'], where: { customer: user, phone: phone, diff --git a/src/modules/queue/domain/entities/ticket.entity.ts b/src/modules/queue/domain/entities/ticket.entity.ts index e5f60d5..fcfec7e 100644 --- a/src/modules/queue/domain/entities/ticket.entity.ts +++ b/src/modules/queue/domain/entities/ticket.entity.ts @@ -10,5 +10,6 @@ export interface QueueTicket extends BaseCoreEntity { date: number; order?: QueueOrder; order_id?: string; + is_printed?: boolean; items: QueueItem[]; } diff --git a/src/modules/queue/domain/queue.orchestrator.ts b/src/modules/queue/domain/queue.orchestrator.ts index 7ce8c81..1bde3a2 100644 --- a/src/modules/queue/domain/queue.orchestrator.ts +++ b/src/modules/queue/domain/queue.orchestrator.ts @@ -29,6 +29,7 @@ import { } from '../data/models/queue.model'; import { CustomerQueueRecommendManager } from './usecases/queue/customer-queue-recommend.manager'; import { GenerateQueueManager } from './usecases/generate-queue.manager'; +import { GenerateTransactionManager } from './usecases/generate-transaction.manager'; @Injectable() export class QueueOrchestrator { @@ -41,12 +42,21 @@ export class QueueOrchestrator { private readonly splitQueueManager: SplitQueueManager, private readonly queueDataService: QueueDataService, private readonly generateQueueManager: GenerateQueueManager, + private readonly generateTransactionManager: GenerateTransactionManager, ) {} async generate(data: any): Promise { return await this.generateQueueManager.generate(data); } + async generateTransaction(data: any): Promise { + return await this.generateTransactionManager.generate(data); + } + + async printTicket(id: string): Promise { + return await this.dataService.printTicket(id); + } + async loginCustomer(id: string): Promise { try { const order = await this.dataService.loginQueue(id); diff --git a/src/modules/queue/domain/usecases/generate-transaction.manager.ts b/src/modules/queue/domain/usecases/generate-transaction.manager.ts new file mode 100644 index 0000000..915c764 --- /dev/null +++ b/src/modules/queue/domain/usecases/generate-transaction.manager.ts @@ -0,0 +1,91 @@ +import { Injectable } from '@nestjs/common'; +import * as moment from 'moment'; +import { TransactionItemModel } from 'src/modules/transaction/transaction/data/models/transaction-item.model'; +import { TicketDataService } from '../../data/services/ticket.service'; +import { QueueOrder } from '../entities/order.entity'; +import { QueueItem } from '../entities/queue-item.entity'; +import { QueueTicket } from '../entities/ticket.entity'; +import { TransactionModel } from 'src/modules/transaction/transaction/data/models/transaction.model'; + +@Injectable() +export class GenerateTransactionManager { + constructor(private readonly ticketService: TicketDataService) {} + + async generate(transaction: TransactionModel) { + 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); + + return existTicket.order; + } else { + const ticket: QueueTicket = { ...customerOrder, items }; + const order: QueueOrder = { ...customerOrder, tickets: [ticket] }; + + const queueOrder = await this.ticketService.createQueueOrder(order); + insertTickets.push(...queueOrder.tickets); + + return queueOrder; + } + } + + 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); + } +} diff --git a/src/modules/queue/domain/usecases/queue/customer-queue-summary.manager.ts b/src/modules/queue/domain/usecases/queue/customer-queue-summary.manager.ts index 342baf3..b4ea2f1 100644 --- a/src/modules/queue/domain/usecases/queue/customer-queue-summary.manager.ts +++ b/src/modules/queue/domain/usecases/queue/customer-queue-summary.manager.ts @@ -9,6 +9,7 @@ export class CustomerQueueSummaryManager extends CustomerQueueManager { customer: ticket.customer, phone: ticket.phone, date: ticket.date, + is_printed: false, summary: this.summaryTicket(ticket), }; }); diff --git a/src/modules/queue/infrastructure/controllers/queue.controller.ts b/src/modules/queue/infrastructure/controllers/queue.controller.ts index 3f3dfec..df33fee 100644 --- a/src/modules/queue/infrastructure/controllers/queue.controller.ts +++ b/src/modules/queue/infrastructure/controllers/queue.controller.ts @@ -1,4 +1,13 @@ -import { Body, Controller, Get, Param, Post, Query, Res } from '@nestjs/common'; +import { + Body, + Controller, + Get, + Param, + Post, + Query, + Res, + UnprocessableEntityException, +} from '@nestjs/common'; import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; @@ -13,17 +22,38 @@ import { LoginQueueDto } from './dto/login-queue.dto'; import { LoginReceiptDto } from './dto/login-receipt.dto'; import { mappingRevertTransaction } from 'src/modules/transaction/transaction/domain/usecases/managers/helpers/mapping-transaction.helper'; import { TransactionType } from 'src/modules/transaction/transaction/constants'; -import { QueueModel } from '../../data/models/queue.model'; +import { QueueModel, QueueTicketModel } from '../../data/models/queue.model'; import * as Gtts from 'gtts'; import { Response } from 'express'; +import { QueueTimeFormula } from '../../domain/usecases/formula/queue-time.formula'; + +import * as moment from 'moment'; @ApiTags(`Queue`) @Controller(`v1/${MODULE_NAME.QUEUE}`) @Public(true) @ApiBearerAuth('JWT') export class QueueController { - constructor(private orchestrator: QueueOrchestrator) {} + constructor( + private orchestrator: QueueOrchestrator, + private readonly queueTimeFormula: QueueTimeFormula, + ) {} + + @Post('dummy') + async dummyChecker(): Promise { + const queueTimes = await this.queueTimeFormula.items( + 'bbb296cc-2a58-40f3-a11f-923adc3e3b44', + ); + const queues = Object.values(queueTimes); + + console.log(queueTimes); + const first = queues[0]; + const last = queues[queues.length - 1] ?? moment().valueOf(); + const average = this.queueTimeFormula.average; + + console.log(first, last, average); + } @Post('generate') async generateQueue(@Body() data: any): Promise { @@ -31,6 +61,18 @@ export class QueueController { return await this.orchestrator.generate(data); } + @Post('create-transaction') + async createTransaction(@Body() data: any): Promise { + mappingRevertTransaction(data, TransactionType.COUNTER); + return await this.orchestrator.generateTransaction(data); + } + + @Post('print-ticket/:id') + async printTicket(@Param('id') id: string): Promise { + if (!id) throw new UnprocessableEntityException('Order id is required'); + return await this.orchestrator.printTicket(id); + } + @Post('register') async registerQueue(@Body() data: RegisterQueueDto): Promise { return await this.orchestrator.create(data); diff --git a/src/modules/queue/queue.module.ts b/src/modules/queue/queue.module.ts index b974dd3..96c6678 100644 --- a/src/modules/queue/queue.module.ts +++ b/src/modules/queue/queue.module.ts @@ -39,6 +39,7 @@ import { ItemQueueModel } from '../item-related/item-queue/data/models/item-queu import { QueueTimeFormula } from './domain/usecases/formula/queue-time.formula'; import { QueueJobController } from './infrastructure/controllers/queue-job.controller'; import { GenerateQueueManager } from './domain/usecases/generate-queue.manager'; +import { GenerateTransactionManager } from './domain/usecases/generate-transaction.manager'; @Module({ imports: [ @@ -81,6 +82,7 @@ import { GenerateQueueManager } from './domain/usecases/generate-queue.manager'; QueueTimeFormula, GenerateQueueManager, + GenerateTransactionManager, ], }) export class QueueModule {}