refactor: more legacy code replaced more on the model and a bit on the admin side

This commit is contained in:
user
2025-10-20 22:08:45 +03:00
parent 2fdb934ec9
commit 2ed74c267d
33 changed files with 1160 additions and 11574 deletions

View File

@@ -1,52 +0,0 @@
import { z } from "zod";
export const emailAccountPayloadModel = z.object({
email: z.string().email().min(6).max(128),
password: z.string().max(128),
agentId: z.string().optional(),
orderId: z.number().int().nullish().optional(),
});
export type EmailAccountPayload = z.infer<typeof emailAccountPayloadModel>;
export const emailAccountModel = emailAccountPayloadModel
.pick({ email: true, agentId: true, orderId: true })
.merge(
z.object({
id: z.number().int(),
used: z.boolean().default(false),
lastActiveCheckAt: z.coerce.string().optional(),
createdAt: z.coerce.string(),
updatedAt: z.coerce.string(),
}),
);
export type EmailAccount = z.infer<typeof emailAccountModel>;
export const emailAccountFullModel = emailAccountPayloadModel.merge(
z.object({
id: z.number().int(),
used: z.boolean().default(false),
createdAt: z.coerce.string(),
updatedAt: z.coerce.string(),
}),
);
export type EmailAccountFull = z.infer<typeof emailAccountFullModel>;
export const inboxModel = z.object({
id: z.number(),
emailId: z.string().default(""),
from: z.string(),
to: z.string().optional(),
cc: z.string().optional(),
subject: z.string(),
body: z.string(),
attachments: z.any().optional(),
emailAccountId: z.number(),
dated: z.coerce.string(),
createdAt: z.coerce.string(),
updatedAt: z.coerce.string(),
});
export type InboxModel = z.infer<typeof inboxModel>;

View File

@@ -14,7 +14,6 @@ export const customerInfoModel = z.object({
zipCode: z.string().min(1).max(21),
address: z.string().min(1),
address2: z.string().optional().nullable(),
orderId: z.number().optional().nullable(),
createdAt: z.coerce.string().optional(),
updatedAt: z.coerce.string().optional(),
});

View File

@@ -3,10 +3,10 @@ import { customerInfo } from "@pkg/db/schema";
import { getError, Logger } from "@pkg/logger";
import { ERROR_CODES, type Result } from "@pkg/result";
import {
customerInfoModel,
type CreateCustomerInfoPayload,
type CustomerInfoModel,
type UpdateCustomerInfoPayload,
customerInfoModel,
type CreateCustomerInfoPayload,
type CustomerInfoModel,
type UpdateCustomerInfoPayload,
} from "./data";
export class CustomerInfoRepository {
@@ -97,41 +97,6 @@ export class CustomerInfoRepository {
}
}
async getCustomerInfoByOrderId(
orderId: number,
): Promise<Result<CustomerInfoModel[]>> {
try {
const results = await this.db.query.customerInfo.findMany({
where: eq(customerInfo.orderId, orderId),
});
const out = [] as CustomerInfoModel[];
for (const result of results) {
const parsed = customerInfoModel.safeParse(result);
if (!parsed.success) {
Logger.error("Failed to parse customer info", result);
continue;
}
out.push(parsed.data);
}
return { data: out };
} catch (e) {
return {
error: getError(
{
code: ERROR_CODES.DATABASE_ERROR,
message: "Failed to fetch customer information",
detail:
"An error occurred while retrieving customer information for the order",
userHint: "Please try again",
actionable: false,
},
e,
),
};
}
}
async createCustomerInfo(
payload: CreateCustomerInfoPayload,
): Promise<Result<number>> {
@@ -151,7 +116,6 @@ export class CustomerInfoRepository {
zipCode: payload.zipCode,
address: payload.address,
address2: payload.address2 || null,
orderId: payload.orderId || null,
})
.returning({ id: customerInfo.id })
.execute();
@@ -231,7 +195,6 @@ export class CustomerInfoRepository {
if (payload.address !== undefined) updateValues.address = payload.address;
if (payload.address2 !== undefined)
updateValues.address2 = payload.address2;
if (payload.orderId !== undefined) updateValues.orderId = payload.orderId;
updateValues.updatedAt = new Date();
await this.db

View File

@@ -1,7 +1,7 @@
import { db } from "@pkg/db";
import type {
CreateCustomerInfoPayload,
UpdateCustomerInfoPayload,
CreateCustomerInfoPayload,
UpdateCustomerInfoPayload,
} from "./data";
import { CustomerInfoRepository } from "./repository";
@@ -20,10 +20,6 @@ export class CustomerInfoUseCases {
return this.repo.getCustomerInfoById(id);
}
async getCustomerInfoByOrderId(orderId: number) {
return this.repo.getCustomerInfoByOrderId(orderId);
}
async createCustomerInfo(payload: CreateCustomerInfoPayload) {
return this.repo.createCustomerInfo(payload);
}

View File

@@ -3,17 +3,19 @@ import { paginationModel } from "../../../core/pagination.utils";
import { encodeCursor } from "../../../core/string.utils";
import { customerInfoModel } from "../../customerinfo/data";
import { paymentDetailsPayloadModel } from "../../paymentinfo/data/entities";
import { flightTicketModel } from "../../ticket/data/entities";
import { productModel } from "../../product/data";
export enum OrderCreationStep {
ACCOUNT_SELECTION = 0,
TICKET_SELECTION = 1,
// TODO: only keep these remove the above 2 steps
CUSTOMER_INFO = 2,
PAYMENT = 2,
SUMMARY = 3,
}
export enum OrderStatus {
PENDING_FULLFILLMENT = "PENDING_FULLFILLMENT",
PENDING_FULFILLMENT = "PENDING_FULFILLMENT",
PARTIALLY_FULFILLED = "PARTIALLY_FULFILLED",
FULFILLED = "FULFILLED",
CANCELLED = "CANCELLED",
@@ -27,13 +29,12 @@ export const orderModel = z.object({
displayPrice: z.coerce.number().min(0),
orderPrice: z.coerce.number().min(0),
fullfilledPrice: z.coerce.number().min(0),
pricePerCustomer: z.coerce.number().min(0),
status: z.nativeEnum(OrderStatus),
flightTicketInfoId: z.number(),
productId: z.number(),
customerInfoId: z.number().nullish().optional(),
emailAccountId: z.number().nullish().optional(),
paymentDetailsId: z.number().nullish().optional(),
createdAt: z.coerce.string(),
@@ -41,37 +42,34 @@ export const orderModel = z.object({
});
export type OrderModel = z.infer<typeof orderModel>;
export const limitedOrderWithTicketInfoModel = orderModel
export const limitedOrderWithProductModel = orderModel
.pick({
id: true,
basePrice: true,
discountAmount: true,
displayPrice: true,
pricePerCustomer: true,
fullfilledPrice: true,
status: true,
})
.merge(
z.object({
flightTicketInfo: flightTicketModel.pick({
product: productModel.pick({
id: true,
departure: true,
arrival: true,
departureDate: true,
returnDate: true,
flightType: true,
passengerCounts: true,
title: true,
description: true,
price: true,
discountPrice: true,
}),
}),
);
export type LimitedOrderWithTicketInfoModel = z.infer<
typeof limitedOrderWithTicketInfoModel
export type LimitedOrderWithProductModel = z.infer<
typeof limitedOrderWithProductModel
>;
export const fullOrderModel = orderModel.merge(
z.object({
flightTicketInfo: flightTicketModel,
customerInfos: z.array(customerInfoModel).default([]),
product: productModel,
customerInfo: customerInfoModel.optional().nullable(),
}),
);
export type FullOrderModel = z.infer<typeof fullOrderModel>;
@@ -108,20 +106,18 @@ export const newOrderModel = orderModel.pick({
discountAmount: true,
orderPrice: true,
fullfilledPrice: true,
pricePerCustomer: true,
flightTicketInfoId: true,
productId: true,
customerInfoId: true,
paymentDetailsId: true,
emailAccountId: true,
});
export type NewOrderModel = z.infer<typeof newOrderModel>;
export const createOrderPayloadModel = z.object({
flightTicketInfo: flightTicketModel.optional(),
flightTicketId: z.number().optional(),
refOIds: z.array(z.number()).nullable().optional(),
product: productModel.optional(),
productId: z.number().optional(),
customerInfo: customerInfoModel,
paymentDetails: paymentDetailsPayloadModel.optional(),
orderModel: newOrderModel,
customerInfos: z.array(customerInfoModel),
flowId: z.string().optional(),
});
export type CreateOrderModel = z.infer<typeof createOrderPayloadModel>;

View File

@@ -77,14 +77,16 @@ export type CardInfo = z.infer<typeof cardInfoModel>;
export const paymentDetailsPayloadModel = z.object({
method: z.enum([PaymentMethod.Card]),
cardDetails: cardInfoModel,
flightTicketInfoId: z.number().int(),
productId: z.number().int(),
orderId: z.number().int(),
});
export type PaymentDetailsPayload = z.infer<typeof paymentDetailsPayloadModel>;
export const paymentDetailsModel = cardInfoModel.merge(
z.object({
id: z.number().int(),
flightTicketInfoId: z.number().int(),
productId: z.number().int(),
orderId: z.number().int(),
createdAt: z.string().datetime(),
updatedAt: z.string().datetime(),
}),

View File

@@ -1,31 +0,0 @@
import { z } from "zod";
import { PackageType, PaymentMethod } from "./enums";
export * from "../../../passengerinfo/data/entities";
// Flight package selection models
export const packageSelectionModel = z.object({
packageType: z.enum([
PackageType.Basic,
PackageType.Flex,
PackageType.Premium,
]),
insurance: z.boolean().default(false),
});
export type PackageSelection = z.infer<typeof packageSelectionModel>;
// payment models
export const cardInfoModel = z.object({
nameOnCard: z.string().min(1).max(255),
number: z.string().max(20),
expiryDate: z.string().max(8),
cvv: z.string().max(6),
});
export type CardInfo = z.infer<typeof cardInfoModel>;
export const paymentInfoModel = z.object({
method: z.enum([PaymentMethod.Card]).default(PaymentMethod.Card),
cardInfo: cardInfoModel,
});
export type PaymentInfo = z.infer<typeof paymentInfoModel>;

View File

@@ -1,43 +0,0 @@
export enum CheckoutStep {
Setup = "SETUP",
Initial = "INITIAL",
Payment = "PAYMENT",
Verification = "VERIFICATION",
Confirmation = "CONFIRMATION",
Complete = "COMPLETE",
}
export const TicketType = {
OneWay: "ONEWAY",
Return: "RETURN",
};
export const CabinClass = {
Economy: "ECONOMY",
PremiumEconomy: "PREMIUM_ECONOMY",
Business: "BUSINESS",
FirstClass: "FIRST_CLASS",
};
export enum Gender {
Male = "male",
Female = "female",
Other = "other",
}
export enum PaymentMethod {
Card = "CARD",
GooglePay = "GOOGLE_PAY",
ApplePay = "APPLEPAY",
}
export enum PassengerType {
Adult = "adult",
Child = "child",
}
export enum PackageType {
Basic = "basic",
Flex = "flex",
Premium = "premium",
}

View File

@@ -1,178 +0,0 @@
import { z } from "zod";
import { CabinClass, TicketType } from "./enums";
export * from "./enums";
export const stationModel = z.object({
id: z.number(),
type: z.string(),
code: z.string(),
name: z.string(),
city: z.string(),
country: z.string(),
});
export type Station = z.infer<typeof stationModel>;
export const iteneraryStationModel = z.object({
station: stationModel,
localTime: z.string(),
utcTime: z.string(),
});
export type IteneraryStation = z.infer<typeof iteneraryStationModel>;
export const seatInfoModel = z.object({
availableSeats: z.number(),
seatClass: z.string(),
});
export type SeatInfo = z.infer<typeof seatInfoModel>;
export const flightPriceDetailsModel = z.object({
currency: z.string(),
basePrice: z.number(),
discountAmount: z.number(),
displayPrice: z.number(),
orderPrice: z.number().nullable().optional(),
appliedCoupon: z.string().nullish().optional(),
couponDescription: z.string().nullish().optional(),
});
export type FlightPriceDetails = z.infer<typeof flightPriceDetailsModel>;
export const airlineModel = z.object({
code: z.string(),
name: z.string(),
imageUrl: z.string().nullable().optional(),
});
export type Airline = z.infer<typeof airlineModel>;
export const flightIteneraryModel = z.object({
flightId: z.string(),
flightNumber: z.string(),
airline: airlineModel,
departure: iteneraryStationModel,
destination: iteneraryStationModel,
durationSeconds: z.number(),
seatInfo: seatInfoModel,
});
export type FlightItenerary = z.infer<typeof flightIteneraryModel>;
export const passengerCountModel = z.object({
adults: z.number().int().min(0),
children: z.number().int().min(0),
});
export type PassengerCount = z.infer<typeof passengerCountModel>;
export function countPassengers(model: PassengerCount) {
return model.adults + model.children;
}
export const bagDimensionsModel = z.object({
length: z.number(),
width: z.number(),
height: z.number(),
});
export type BagDimensions = z.infer<typeof bagDimensionsModel>;
export const bagDetailsModel = z.object({
price: z.number(),
weight: z.number(),
unit: z.string(),
dimensions: bagDimensionsModel,
});
export type BagDetails = z.infer<typeof bagDetailsModel>;
export const allBagDetailsModel = z.object({
personalBags: bagDetailsModel,
handBags: bagDetailsModel,
checkedBags: bagDetailsModel,
});
export type AllBagDetails = z.infer<typeof allBagDetailsModel>;
// INFO: If you are to array-ificate it, you can just modify the details
// key below so that the user's order thing is not disrupted
export const bagsInfoModel = z.object({
includedPersonalBags: z.number().default(1),
includedHandBags: z.number().default(0),
includedCheckedBags: z.number().default(0),
hasHandBagsSupport: z.boolean().default(true),
hasCheckedBagsSupport: z.boolean().default(true),
details: allBagDetailsModel,
});
export type BagsInfo = z.infer<typeof bagsInfoModel>;
export const flightTicketModel = z.object({
id: z.number().int(),
ticketId: z.string(),
// For lookup purposes, we need these on the top level
departure: z.string(),
arrival: z.string(),
departureDate: z.coerce.string(),
returnDate: z.coerce.string().default(""),
dates: z.array(z.string()),
flightType: z.enum([TicketType.OneWay, TicketType.Return]),
flightIteneraries: z.object({
outbound: z.array(flightIteneraryModel),
inbound: z.array(flightIteneraryModel),
}),
priceDetails: flightPriceDetailsModel,
refundable: z.boolean(),
passengerCounts: passengerCountModel,
cabinClass: z.string(),
bagsInfo: bagsInfoModel,
lastAvailable: z.object({ availableSeats: z.number() }),
shareId: z.string(),
checkoutUrl: z.string(),
isCache: z.boolean().nullish().optional(),
refOIds: z.array(z.coerce.number()).nullish().optional(),
createdAt: z.coerce.string(),
updatedAt: z.coerce.string(),
});
export type FlightTicket = z.infer<typeof flightTicketModel>;
export const limitedFlightTicketModel = flightTicketModel.pick({
id: true,
departure: true,
arrival: true,
departureDate: true,
returnDate: true,
flightType: true,
dates: true,
priceDetails: true,
passengerCounts: true,
cabinClass: true,
});
export type LimitedFlightTicket = z.infer<typeof limitedFlightTicketModel>;
// INFO: ticket search models
export const ticketSearchPayloadModel = z.object({
sessionId: z.string(),
ticketType: z.enum([TicketType.OneWay, TicketType.Return]),
cabinClass: z.enum([
CabinClass.Economy,
CabinClass.PremiumEconomy,
CabinClass.Business,
CabinClass.FirstClass,
]),
departure: z.string().min(3),
arrival: z.string().min(3),
passengerCounts: passengerCountModel,
departureDate: z.coerce.string().min(3),
returnDate: z.coerce.string(),
loadMore: z.boolean().default(false),
meta: z.record(z.string(), z.any()).optional(),
couponCode: z.string().optional(),
});
export type TicketSearchPayload = z.infer<typeof ticketSearchPayloadModel>;
export const ticketSearchDTO = z.object({
sessionId: z.string(),
ticketSearchPayload: ticketSearchPayloadModel,
providers: z.array(z.string()).optional(),
});
export type TicketSearchDTO = z.infer<typeof ticketSearchDTO>;