212 lines
6.0 KiB
TypeScript
212 lines
6.0 KiB
TypeScript
import {
|
|
Body,
|
|
Controller,
|
|
Get,
|
|
Param,
|
|
Post,
|
|
Res,
|
|
UnprocessableEntityException,
|
|
} from '@nestjs/common';
|
|
import { ApiTags } from '@nestjs/swagger';
|
|
import { Public } from 'src/core/guards';
|
|
import { TransactionDto } from './dto/booking-order.dto';
|
|
import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity';
|
|
import { TransactionDataService } from 'src/modules/transaction/transaction/data/services/transaction-data.service';
|
|
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
|
|
import { MidtransService } from 'src/modules/configuration/midtrans/data/services/midtrans.service';
|
|
import { CreateBookingManager } from '../domain/usecases/managers/create-booking.manager';
|
|
import * as QRCode from 'qrcode';
|
|
import { Gate } from 'src/core/response/domain/decorators/pagination.response';
|
|
import { Response } from 'express';
|
|
import {
|
|
RescheduleRequestDTO,
|
|
RescheduleVerificationOTP,
|
|
} from './dto/reschedule.dto';
|
|
import { RescheduleVerificationManager } from '../domain/usecases/managers/reschedule-verification.manager';
|
|
import { RescheduleManager } from '../domain/usecases/managers/reschedule.manager';
|
|
import { STATUS } from 'src/core/strings/constants/base.constants';
|
|
import * as moment from 'moment';
|
|
|
|
@ApiTags('Booking Order')
|
|
@Controller('v1/booking')
|
|
@Public(true)
|
|
export class BookingOrderController {
|
|
constructor(
|
|
private createBooking: CreateBookingManager,
|
|
private serviceData: TransactionDataService,
|
|
private midtransService: MidtransService,
|
|
private rescheduleVerification: RescheduleVerificationManager,
|
|
private rescheduleManager: RescheduleManager,
|
|
) {}
|
|
|
|
@Post()
|
|
async create(@Body() data: TransactionDto) {
|
|
const payload: Partial<TransactionEntity> = data;
|
|
|
|
this.createBooking.setData(payload as any);
|
|
this.createBooking.setService(
|
|
this.serviceData,
|
|
TABLE_NAME.TRANSACTION,
|
|
this.midtransService,
|
|
);
|
|
await this.createBooking.execute();
|
|
const result = await this.createBooking.getResult();
|
|
const {
|
|
invoice_code,
|
|
status,
|
|
payment_midtrans_token,
|
|
payment_midtrans_url,
|
|
id,
|
|
} = result;
|
|
|
|
return {
|
|
id,
|
|
invoice_code,
|
|
status,
|
|
payment_midtrans_token,
|
|
payment_midtrans_url,
|
|
};
|
|
}
|
|
|
|
@Post('reschedule')
|
|
async reschedule(@Body() data: RescheduleRequestDTO) {
|
|
const transaction = await this.serviceData.getTransactionWithReschedule(
|
|
data.booking_id,
|
|
);
|
|
|
|
const today = moment().startOf('day');
|
|
const rescheduleDate = moment(data.reschedule_date, 'DD-MM-YYYY');
|
|
const rescheduleDateStartOfDay = rescheduleDate.startOf('day');
|
|
|
|
//TODO: validate session period priority
|
|
|
|
if (rescheduleDateStartOfDay.isSameOrBefore(today)) {
|
|
throw new UnprocessableEntityException(
|
|
'Reschedule date must be in the future',
|
|
);
|
|
}
|
|
|
|
if (!transaction) {
|
|
throw new UnprocessableEntityException('Transaction not found');
|
|
}
|
|
|
|
if (transaction.status !== STATUS.SETTLED) {
|
|
throw new UnprocessableEntityException('Transaction is not settled');
|
|
}
|
|
|
|
if (transaction.children_transactions.length > 0) {
|
|
throw new UnprocessableEntityException('Transaction already rescheduled');
|
|
}
|
|
|
|
if (transaction.parent_id) {
|
|
throw new UnprocessableEntityException('Transaction is a reschedule');
|
|
}
|
|
|
|
const result = await this.rescheduleVerification.saveVerification(data);
|
|
const maskedPhoneNumber = result.phone_number.replace(/.(?=.{4})/g, '*');
|
|
result.phone_number = maskedPhoneNumber;
|
|
|
|
return `Verification code sent to ${maskedPhoneNumber}`;
|
|
}
|
|
|
|
@Post('reschedule/verification')
|
|
async verificationReschedule(@Body() data: RescheduleVerificationOTP) {
|
|
const result = await this.rescheduleVerification.verifyOtp(
|
|
data.booking_id,
|
|
+data.code,
|
|
);
|
|
|
|
const reschedule = await this.rescheduleManager.reschedule(result);
|
|
const transaction = await this.get(reschedule.id);
|
|
|
|
return {
|
|
id: reschedule.id,
|
|
phone_number: result.phone_number,
|
|
name: result.name,
|
|
reschedule_date: result.reschedule_date,
|
|
transaction,
|
|
};
|
|
}
|
|
|
|
@Get(':id')
|
|
async get(@Param('id') transactionId: string) {
|
|
const data = await this.serviceData.getOneByOptions({
|
|
relations: ['items', 'items.item', 'items.item.time_group'],
|
|
where: { id: transactionId },
|
|
});
|
|
|
|
const {
|
|
customer_name,
|
|
customer_phone,
|
|
booking_date,
|
|
invoice_code,
|
|
status,
|
|
id,
|
|
items,
|
|
} = data;
|
|
|
|
const usageItems = items.map((item) => {
|
|
const itemData = item.item;
|
|
const timeGroupData = itemData.time_group;
|
|
const { id: groupId, name, start_time, end_time } = timeGroupData;
|
|
const {
|
|
id,
|
|
item_id,
|
|
item_name,
|
|
item_price,
|
|
item_category_name,
|
|
total_price,
|
|
total_net_price,
|
|
qty,
|
|
qty_remaining,
|
|
} = item;
|
|
return {
|
|
id,
|
|
item_id,
|
|
item_name,
|
|
item_price,
|
|
item_category_name,
|
|
total_price,
|
|
total_net_price,
|
|
qty,
|
|
qty_remaining,
|
|
time_group: {
|
|
id: groupId,
|
|
name,
|
|
start_time,
|
|
end_time,
|
|
},
|
|
};
|
|
});
|
|
|
|
// Mask customer_phone with * and keep last 4 numbers
|
|
let maskedCustomerPhone = customer_phone;
|
|
if (typeof customer_phone === 'string' && customer_phone.length > 4) {
|
|
const last4 = customer_phone.slice(-4);
|
|
maskedCustomerPhone = '*'.repeat(customer_phone.length - 4) + last4;
|
|
}
|
|
|
|
return {
|
|
customer_name,
|
|
customer_phone: maskedCustomerPhone,
|
|
booking_date,
|
|
invoice_code,
|
|
status,
|
|
id,
|
|
items: usageItems,
|
|
};
|
|
}
|
|
|
|
@Gate()
|
|
@Get('qrcode/:id')
|
|
async getQRcode(@Param('id') id: string, @Res() res: Response) {
|
|
console.log(QRCode);
|
|
const qrData = id;
|
|
const data = await QRCode.toDataURL(qrData);
|
|
res.setHeader('Content-Type', 'image/png');
|
|
const base64Data = data.split(',')[1];
|
|
const buffer = Buffer.from(base64Data, 'base64');
|
|
res.send(buffer);
|
|
}
|
|
}
|