change order flow
This commit is contained in:
@@ -5,12 +5,12 @@ export const paginationQuerySchema = z.object({
|
||||
page: z.coerce
|
||||
.number("Must be number.")
|
||||
.int("Must be integer.")
|
||||
.min(1, "Minimum 1.")
|
||||
.min(1, "Min 1.")
|
||||
.default(1),
|
||||
per_page: z.coerce
|
||||
.number("Must be number.")
|
||||
.int("Must be integer.")
|
||||
.min(1, "Minimum 1.")
|
||||
.min(1, "Min 1.")
|
||||
.default(100),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { PaymentError } from "@/common/errors/payment.error";
|
||||
import { AbstractPaymentService } from "@/common/services/payment-service/abstract.payment-service";
|
||||
import { midtransConfig } from "@/configs/midtrans.config";
|
||||
import type { OrderDetail } from "@/database/entities/order-detail.entity";
|
||||
import type { Order } from "@/database/entities/order.entity";
|
||||
import { RoomType } from "@/database/enums/room-type.enum";
|
||||
|
||||
type CreateTransactionResponseSuccess = {
|
||||
token: string;
|
||||
@@ -22,41 +20,17 @@ export class MidtransPaymentService extends AbstractPaymentService {
|
||||
this._basicAuth = `Basic ${Buffer.from(`${midtransConfig.serverKey}:`).toBase64()}`;
|
||||
}
|
||||
|
||||
private calculateOrderDetailsPrice(orderDetails: OrderDetail[]): number {
|
||||
let price = 0;
|
||||
for (const orderDetail of orderDetails) {
|
||||
switch (orderDetail.roomType) {
|
||||
case RoomType.double:
|
||||
price += orderDetail.order.package.doublePrice;
|
||||
break;
|
||||
case RoomType.triple:
|
||||
price += orderDetail.order.package.triplePrice;
|
||||
break;
|
||||
case RoomType.quad:
|
||||
price += orderDetail.order.package.quadPrice;
|
||||
break;
|
||||
case RoomType.infant:
|
||||
price += orderDetail.order.package.infantPrice ?? 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return price;
|
||||
private calculateOrderPrice(order: Order): number {
|
||||
return (
|
||||
order.package.quadPrice * order.quad +
|
||||
order.package.triplePrice * order.triple +
|
||||
order.package.doublePrice * order.double +
|
||||
(order.package.infantPrice ?? 0) * order.infant
|
||||
);
|
||||
}
|
||||
|
||||
public async createPaymentUrl(order: Order): Promise<string> {
|
||||
const doubleOrderDetails = order.details.filter(
|
||||
(orderDetail) => orderDetail.roomType === RoomType.double,
|
||||
);
|
||||
const tripleOrderDetails = order.details.filter(
|
||||
(orderDetail) => orderDetail.roomType === RoomType.double,
|
||||
);
|
||||
const quadOrderDetails = order.details.filter(
|
||||
(orderDetail) => orderDetail.roomType === RoomType.double,
|
||||
);
|
||||
const infantOrderDetails = order.details.filter(
|
||||
(orderDetail) => orderDetail.roomType === RoomType.double,
|
||||
);
|
||||
const price = this.calculateOrderPrice(order);
|
||||
|
||||
const response = await fetch(`${midtransConfig.baseUrl}/transactions`, {
|
||||
method: "POST",
|
||||
@@ -68,55 +42,18 @@ export class MidtransPaymentService extends AbstractPaymentService {
|
||||
body: JSON.stringify({
|
||||
transaction_details: {
|
||||
order_id: order.id,
|
||||
gross_amount: this.calculateOrderDetailsPrice(
|
||||
order.details.getItems(),
|
||||
),
|
||||
gross_amount: this.calculateOrderPrice(order),
|
||||
},
|
||||
item_details: [
|
||||
doubleOrderDetails.length > 0
|
||||
? {
|
||||
id: doubleOrderDetails[0].id,
|
||||
price: order.package.doublePrice,
|
||||
quantity: doubleOrderDetails.length,
|
||||
name: `${order.package.package.name} / Double`,
|
||||
brand: "GoUmrah",
|
||||
category: "Paket",
|
||||
merchant_name: "GoUmrah",
|
||||
}
|
||||
: undefined,
|
||||
tripleOrderDetails.length > 0
|
||||
? {
|
||||
id: tripleOrderDetails[0].id,
|
||||
price: order.package.triplePrice,
|
||||
quantity: tripleOrderDetails.length,
|
||||
name: `${order.package.package.name} / Triple`,
|
||||
brand: "GoUmrah",
|
||||
category: "Paket",
|
||||
merchant_name: "GoUmrah",
|
||||
}
|
||||
: undefined,
|
||||
quadOrderDetails.length > 0
|
||||
? {
|
||||
id: quadOrderDetails[0].id,
|
||||
price: order.package.quadPrice,
|
||||
quantity: quadOrderDetails.length,
|
||||
name: `${order.package.package.name} / Quad`,
|
||||
brand: "GoUmrah",
|
||||
category: "Paket",
|
||||
merchant_name: "GoUmrah",
|
||||
}
|
||||
: undefined,
|
||||
infantOrderDetails.length > 0
|
||||
? {
|
||||
id: infantOrderDetails[0].id,
|
||||
price: order.package.infantPrice,
|
||||
quantity: infantOrderDetails.length,
|
||||
name: `${order.package.package.name} / Infant`,
|
||||
brand: "GoUmrah",
|
||||
category: "Paket",
|
||||
merchant_name: "GoUmrah",
|
||||
}
|
||||
: undefined,
|
||||
{
|
||||
id: order.id,
|
||||
price,
|
||||
quantity: order.quad + order.triple + order.double + order.infant,
|
||||
name: `${order.package.package.name}`,
|
||||
brand: "GoUmrah",
|
||||
category: "Paket",
|
||||
merchant_name: "GoUmrah",
|
||||
},
|
||||
],
|
||||
customer_details: {
|
||||
first_name: order.name,
|
||||
|
||||
@@ -6,13 +6,13 @@ export const _env = z
|
||||
SERVER_PORT: z.coerce
|
||||
.number("Must be number.")
|
||||
.int("Must be integer.")
|
||||
.min(0, "Min 0."),
|
||||
.min(0, "Minimum0."),
|
||||
|
||||
DATABASE_HOST: z.string("Must be string.").nonempty("Must not empty."),
|
||||
DATABASE_PORT: z.coerce
|
||||
.number("Must be number.")
|
||||
.int("Must be integer.")
|
||||
.min(0, "Min 0."),
|
||||
.min(0, "Minimum0."),
|
||||
DATABASE_USERNAME: z.string("Must be string.").nonempty("Must not empty."),
|
||||
DATABASE_PASSWORD: z.string("Must be string.").nonempty("Must not empty."),
|
||||
DATABASE_NAME: z.string("Must be string.").nonempty("Must not empty."),
|
||||
@@ -49,7 +49,7 @@ export const _env = z
|
||||
MAIL_PORT: z.coerce
|
||||
.number("Must be number.")
|
||||
.int("Must be integer.")
|
||||
.min(0, "Min 0."),
|
||||
.min(0, "Minimum0."),
|
||||
MAIL_USERNAME: z.string("Must be string.").nonempty("Must not empty."),
|
||||
MAIL_PASSWORD: z.string("Must be string.").nonempty("Must not empty."),
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { Order } from "@/database/entities/order.entity";
|
||||
import { RoomType } from "@/database/enums/room-type.enum";
|
||||
import {
|
||||
Entity,
|
||||
Enum,
|
||||
ManyToOne,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
type Rel,
|
||||
} from "@mikro-orm/core";
|
||||
|
||||
@Entity()
|
||||
export class OrderDetail {
|
||||
@PrimaryKey({ type: "varchar", length: 30 })
|
||||
id!: string;
|
||||
|
||||
@ManyToOne(() => Order)
|
||||
order!: Rel<Order>;
|
||||
|
||||
@Enum({ items: () => RoomType })
|
||||
roomType!: RoomType;
|
||||
|
||||
@Property({
|
||||
type: "timestamp",
|
||||
onCreate: () => new Date(),
|
||||
})
|
||||
createdAt!: Date;
|
||||
|
||||
@Property({
|
||||
type: "timestamp",
|
||||
onCreate: () => new Date(),
|
||||
onUpdate: () => new Date(),
|
||||
})
|
||||
updatedAt!: Date;
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
import { OrderDetail } from "@/database/entities/order-detail.entity";
|
||||
import { PackageDetail } from "@/database/entities/package-detail.entity";
|
||||
import { Partner } from "@/database/entities/partner.entity";
|
||||
import { Verification } from "@/database/entities/verification.entity";
|
||||
import { Kit } from "@/database/enums/kit.enum";
|
||||
import { OrderType } from "@/database/enums/order-type.enum";
|
||||
import {
|
||||
Collection,
|
||||
Entity,
|
||||
Enum,
|
||||
ManyToOne,
|
||||
OneToMany,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
type Rel,
|
||||
@@ -20,18 +18,45 @@ export class Order {
|
||||
@ManyToOne(() => PackageDetail)
|
||||
package!: Rel<PackageDetail>;
|
||||
|
||||
@Property({ type: "int", unsigned: true })
|
||||
quad!: number;
|
||||
|
||||
@Property({ type: "int", unsigned: true })
|
||||
triple!: number;
|
||||
|
||||
@Property({ type: "int", unsigned: true })
|
||||
double!: number;
|
||||
|
||||
@Property({ type: "int", unsigned: true })
|
||||
infant!: number;
|
||||
|
||||
@Enum({ items: () => OrderType })
|
||||
type!: OrderType;
|
||||
|
||||
@Property({ type: "int", unsigned: true })
|
||||
quadDownPaymentPercentage!: number;
|
||||
|
||||
@Property({ type: "int", unsigned: true })
|
||||
tripleDownPaymentPercentage!: number;
|
||||
|
||||
@Property({ type: "int", unsigned: true })
|
||||
doubleDownPaymentPercentage!: number;
|
||||
|
||||
@Property({ type: "int", unsigned: true })
|
||||
infantDownPaymentPercentage!: number;
|
||||
|
||||
@Enum({ items: () => Kit })
|
||||
kit!: Kit;
|
||||
|
||||
@Property({ type: "int", unsigned: true })
|
||||
vaccine!: number;
|
||||
|
||||
@Property({ type: "varchar", length: 100 })
|
||||
name!: string;
|
||||
|
||||
@Property({ type: "varchar", length: 20 })
|
||||
whatsapp!: string;
|
||||
|
||||
@ManyToOne(() => Verification, { nullable: true })
|
||||
verification!: Rel<Verification> | null;
|
||||
|
||||
@ManyToOne(() => Partner, { nullable: true })
|
||||
partner!: Rel<Partner | null>;
|
||||
|
||||
@Property({ type: "timestamp", nullable: true })
|
||||
expiredAt!: Date | null;
|
||||
|
||||
@@ -53,9 +78,4 @@ export class Order {
|
||||
onUpdate: () => new Date(),
|
||||
})
|
||||
updatedAt!: Date;
|
||||
|
||||
// Collections
|
||||
|
||||
@OneToMany(() => OrderDetail, (orderDetail) => orderDetail.order)
|
||||
details = new Collection<OrderDetail>(this);
|
||||
}
|
||||
|
||||
5
src/database/enums/kit.enum.ts
Normal file
5
src/database/enums/kit.enum.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export enum Kit {
|
||||
minimal = "minimal",
|
||||
withoutSuitcase = "without_suitcase",
|
||||
full = "full",
|
||||
}
|
||||
4
src/database/enums/order-type.enum.ts
Normal file
4
src/database/enums/order-type.enum.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export enum OrderType {
|
||||
bookingSeat = "booking_seat",
|
||||
downPayment = "down_payment",
|
||||
}
|
||||
@@ -14,8 +14,8 @@ export const airlineRequestSchema = z.object({
|
||||
skytrax_rating: z
|
||||
.number("Must be number.")
|
||||
.int("Must be integer.")
|
||||
.min(1, "Minimum 1.")
|
||||
.max(5, "Maximum 5."),
|
||||
.min(1, "Min 1.")
|
||||
.max(5, "Max 5."),
|
||||
skytrax_type: z.enum(
|
||||
SkytraxType,
|
||||
"Must be either 'full_service' or 'low_cost'.",
|
||||
|
||||
@@ -12,8 +12,8 @@ export const hotelRequestSchema = z.object({
|
||||
star: z
|
||||
.number("Must be number.")
|
||||
.int("Must be integer.")
|
||||
.min(1, "Minimum 1.")
|
||||
.max(7, "Maximum 7."),
|
||||
.min(1, "Min 1.")
|
||||
.max(7, "Max 7."),
|
||||
images: z
|
||||
.array(
|
||||
z.base64("Must be base64 string.").nonempty("Must not empty."),
|
||||
|
||||
@@ -12,22 +12,15 @@ import type {
|
||||
ListResponse,
|
||||
SingleResponse,
|
||||
} from "@/common/types";
|
||||
import { generateRandomCode } from "@/common/utils";
|
||||
import { OrderDetail } from "@/database/entities/order-detail.entity";
|
||||
import { Order } from "@/database/entities/order.entity";
|
||||
import { PackageDetail } from "@/database/entities/package-detail.entity";
|
||||
import { Partner } from "@/database/entities/partner.entity";
|
||||
import { Verification } from "@/database/entities/verification.entity";
|
||||
import { VerificationType } from "@/database/enums/verification-type.enum";
|
||||
import { orm } from "@/database/orm";
|
||||
import type { OrderMapper } from "@/modules/order/order.mapper";
|
||||
import {
|
||||
orderParamsSchema,
|
||||
orderRequestSchema,
|
||||
orderVerifyRequestSchema,
|
||||
} from "@/modules/order/order.schemas";
|
||||
import type { OrderResponse } from "@/modules/order/order.types";
|
||||
import * as dateFns from "date-fns";
|
||||
import { Router, type Request, type Response } from "express";
|
||||
import { ulid } from "ulid";
|
||||
|
||||
@@ -63,22 +56,22 @@ export class OrderController extends Controller {
|
||||
} satisfies ErrorResponse);
|
||||
}
|
||||
|
||||
const verification = orm.em.create(Verification, {
|
||||
id: ulid(),
|
||||
code: generateRandomCode(6, "0123456789"),
|
||||
type: VerificationType.createOrder,
|
||||
expiredAt: dateFns.addHours(new Date(), 1),
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
const order = orm.em.create(Order, {
|
||||
id: ulid(),
|
||||
package: packageDetail,
|
||||
quad: body.quad,
|
||||
triple: body.triple,
|
||||
double: body.double,
|
||||
infant: body.infant,
|
||||
type: body.type,
|
||||
quadDownPaymentPercentage: body.quad_down_payment_percentage,
|
||||
tripleDownPaymentPercentage: body.triple_down_payment_percentage,
|
||||
doubleDownPaymentPercentage: body.double_down_payment_percentage,
|
||||
infantDownPaymentPercentage: body.infant_down_payment_percentage,
|
||||
kit: body.kit,
|
||||
vaccine: body.vaccine,
|
||||
name: body.name,
|
||||
whatsapp: body.whatsapp,
|
||||
verification,
|
||||
partner: null,
|
||||
expiredAt: null,
|
||||
purchasedAt: null,
|
||||
finishedAt: null,
|
||||
@@ -86,27 +79,21 @@ export class OrderController extends Controller {
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
for (const roomType of body.room_types) {
|
||||
order.details.add(
|
||||
orm.em.create(OrderDetail, {
|
||||
id: ulid(),
|
||||
order,
|
||||
roomType,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
await orm.em.flush();
|
||||
|
||||
const paymentUrl = await this.paymentService.createPaymentUrl(order);
|
||||
|
||||
return res.status(201).json({
|
||||
data: {
|
||||
message:
|
||||
"Order created successfully. Please check your email for verification.",
|
||||
...this.mapper.mapEntityToResponse(order),
|
||||
payment_url: paymentUrl,
|
||||
},
|
||||
errors: null,
|
||||
} satisfies SingleResponse);
|
||||
} satisfies SingleResponse<
|
||||
OrderResponse & {
|
||||
payment_url: string;
|
||||
}
|
||||
>);
|
||||
}
|
||||
|
||||
async list(_req: Request, res: Response) {
|
||||
@@ -123,8 +110,11 @@ export class OrderController extends Controller {
|
||||
const orders = await orm.em.find(
|
||||
Order,
|
||||
{
|
||||
verification: null,
|
||||
partner: req.partner,
|
||||
package: {
|
||||
package: {
|
||||
partner: req.partner,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
limit: query.per_page,
|
||||
@@ -159,8 +149,11 @@ export class OrderController extends Controller {
|
||||
Order,
|
||||
{
|
||||
id: params.id,
|
||||
verification: null,
|
||||
partner: req.partner,
|
||||
package: {
|
||||
package: {
|
||||
partner: req.partner,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
populate: ["*"],
|
||||
@@ -198,8 +191,11 @@ export class OrderController extends Controller {
|
||||
Order,
|
||||
{
|
||||
id: params.id,
|
||||
verification: null,
|
||||
partner: req.partner,
|
||||
package: {
|
||||
package: {
|
||||
partner: req.partner,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
populate: ["*"],
|
||||
@@ -229,94 +225,6 @@ export class OrderController extends Controller {
|
||||
} satisfies SingleResponse<OrderResponse>);
|
||||
}
|
||||
|
||||
async verify(req: Request, res: Response) {
|
||||
const parseParamsResult = orderParamsSchema.safeParse(req.params);
|
||||
if (!parseParamsResult.success) {
|
||||
return this.handleZodError(parseParamsResult.error, res, "params");
|
||||
}
|
||||
const params = parseParamsResult.data;
|
||||
|
||||
const parseBodyResult = orderVerifyRequestSchema.safeParse(req.body);
|
||||
if (!parseBodyResult.success) {
|
||||
return this.handleZodError(parseBodyResult.error, res, "body");
|
||||
}
|
||||
const body = parseBodyResult.data;
|
||||
|
||||
const order = await orm.em.findOne(
|
||||
Order,
|
||||
{ id: params.id },
|
||||
{
|
||||
populate: ["*"],
|
||||
},
|
||||
);
|
||||
if (!order) {
|
||||
return res.status(404).json({
|
||||
data: null,
|
||||
errors: [
|
||||
{
|
||||
path: "id",
|
||||
location: "params",
|
||||
message: "Order not found.",
|
||||
},
|
||||
],
|
||||
} satisfies ErrorResponse);
|
||||
}
|
||||
|
||||
if (order.verification === null) {
|
||||
return res.status(400).json({
|
||||
data: null,
|
||||
errors: [
|
||||
{
|
||||
message: "Order is already verified.",
|
||||
},
|
||||
],
|
||||
} satisfies ErrorResponse);
|
||||
}
|
||||
|
||||
if (order.verification.code !== body.code) {
|
||||
return res.status(400).json({
|
||||
data: null,
|
||||
errors: [
|
||||
{
|
||||
path: "code",
|
||||
location: "body",
|
||||
message: "Incorrect.",
|
||||
},
|
||||
],
|
||||
} satisfies ErrorResponse);
|
||||
}
|
||||
|
||||
orm.em.remove(order.verification);
|
||||
|
||||
const partners = await orm.em.findAll(Partner, { populate: ["*"] });
|
||||
const partner = partners.toSorted(
|
||||
(a, b) =>
|
||||
a.orders.filter((order) => order.finishedAt === null).length -
|
||||
b.orders.filter((order) => order.finishedAt === null).length,
|
||||
)[0];
|
||||
|
||||
order.verification = null;
|
||||
order.partner = partner;
|
||||
order.expiredAt = dateFns.addHours(new Date(), 24);
|
||||
order.updatedAt = new Date();
|
||||
|
||||
await orm.em.flush();
|
||||
|
||||
const paymentUrl = await this.paymentService.createPaymentUrl(order);
|
||||
|
||||
return res.status(200).json({
|
||||
data: {
|
||||
...this.mapper.mapEntityToResponse(order),
|
||||
payment_url: paymentUrl,
|
||||
},
|
||||
errors: null,
|
||||
} satisfies SingleResponse<
|
||||
OrderResponse & {
|
||||
payment_url: string;
|
||||
}
|
||||
>);
|
||||
}
|
||||
|
||||
async delete(_req: Request, res: Response) {
|
||||
const req = _req as Request & PartnerRequestPlugin;
|
||||
|
||||
@@ -328,7 +236,14 @@ export class OrderController extends Controller {
|
||||
|
||||
const order = await orm.em.findOne(
|
||||
Order,
|
||||
{ id: params.id, verification: null, partner: req.partner },
|
||||
{
|
||||
id: params.id,
|
||||
package: {
|
||||
package: {
|
||||
partner: req.partner,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
populate: ["*"],
|
||||
},
|
||||
@@ -372,11 +287,6 @@ export class OrderController extends Controller {
|
||||
isPartnerMiddleware(this.jwtService),
|
||||
this.finish.bind(this),
|
||||
);
|
||||
router.put(
|
||||
"/:id/verify",
|
||||
createOrmContextMiddleware,
|
||||
this.verify.bind(this),
|
||||
);
|
||||
router.delete(
|
||||
"/:id",
|
||||
createOrmContextMiddleware,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { phoneNumberSchema } from "@/common/schemas";
|
||||
import { RoomType } from "@/database/enums/room-type.enum";
|
||||
import { Kit } from "@/database/enums/kit.enum";
|
||||
import { OrderType } from "@/database/enums/order-type.enum";
|
||||
import z from "zod";
|
||||
|
||||
export const orderRequestSchema = z.object({
|
||||
@@ -7,20 +8,38 @@ export const orderRequestSchema = z.object({
|
||||
.ulid("Must be ulid string.")
|
||||
.nonempty("Must not empty.")
|
||||
.max(30, "Max 30 characters."),
|
||||
quad: z.number("Must be number.").int("Must be integer.").min(0, "Min 0."),
|
||||
triple: z.number("Must be number.").int("Must be integer.").min(0, "Min 0."),
|
||||
double: z.number("Must be number.").int("Must be integer.").min(0, "Min 0."),
|
||||
infant: z.number("Must be number.").int("Must be integer.").min(0, "Min 0."),
|
||||
type: z.enum(OrderType, "Must be either 'booking_seat' or 'down_payment'."),
|
||||
quad_down_payment_percentage: z
|
||||
.number("Must be number.")
|
||||
.int("Must be integer")
|
||||
.min(25, "Min 25.")
|
||||
.max(100, "Max 100."),
|
||||
triple_down_payment_percentage: z
|
||||
.number("Must be number.")
|
||||
.int("Must be integer")
|
||||
.min(25, "Min 25.")
|
||||
.max(100, "Max 100."),
|
||||
double_down_payment_percentage: z
|
||||
.number("Must be number.")
|
||||
.int("Must be integer")
|
||||
.min(25, "Min 25.")
|
||||
.max(100, "Max 100."),
|
||||
infant_down_payment_percentage: z
|
||||
.number("Must be number.")
|
||||
.int("Must be integer")
|
||||
.min(25, "Min 25.")
|
||||
.max(100, "Max 100."),
|
||||
kit: z.enum(Kit, "Must be either 'minimal', 'without_suitcase', or 'full'."),
|
||||
vaccine: z.number("Must be number.").int("Must be integer.").min(0, "Min 0."),
|
||||
name: z
|
||||
.string("Must be string.")
|
||||
.nonempty("Must not empty.")
|
||||
.max(100, "Max 100 characters."),
|
||||
whatsapp: phoneNumberSchema,
|
||||
room_types: z
|
||||
.array(
|
||||
z.enum(
|
||||
RoomType,
|
||||
"Must be either 'double', 'triple', 'quad', or 'infant'.",
|
||||
),
|
||||
"Must be array.",
|
||||
)
|
||||
.nonempty("Must not empty."),
|
||||
});
|
||||
|
||||
export const orderVerifyRequestSchema = z.object({
|
||||
|
||||
@@ -12,7 +12,7 @@ export const testimonyRequestSchema = z.object({
|
||||
rating: z
|
||||
.number("Must be number.")
|
||||
.int("Must be integer.")
|
||||
.min(1, "Min 1.")
|
||||
.min(1, "Minimum1.")
|
||||
.max(5, "Max 5."),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user