add hotel schedule (again)
This commit is contained in:
36
src/database/entities/hotel-schedule.entity.ts
Normal file
36
src/database/entities/hotel-schedule.entity.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { Hotel } from "@/database/entities/hotel.entity";
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
ManyToOne,
|
||||||
|
PrimaryKey,
|
||||||
|
Property,
|
||||||
|
type Rel,
|
||||||
|
} from "@mikro-orm/core";
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class HotelSchedule {
|
||||||
|
@PrimaryKey({ type: "varchar", length: 30 })
|
||||||
|
id!: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => Hotel)
|
||||||
|
hotel!: Rel<Hotel>;
|
||||||
|
|
||||||
|
@Property({ type: "date" })
|
||||||
|
checkIn!: Date;
|
||||||
|
|
||||||
|
@Property({ type: "date" })
|
||||||
|
checkOut!: Date;
|
||||||
|
|
||||||
|
@Property({
|
||||||
|
type: "timestamp",
|
||||||
|
onCreate: () => new Date(),
|
||||||
|
})
|
||||||
|
createdAt!: Date;
|
||||||
|
|
||||||
|
@Property({
|
||||||
|
type: "timestamp",
|
||||||
|
onCreate: () => new Date(),
|
||||||
|
onUpdate: () => new Date(),
|
||||||
|
})
|
||||||
|
updatedAt!: Date;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { FlightSchedule } from "@/database/entities/flight-schedule.entity";
|
import { FlightSchedule } from "@/database/entities/flight-schedule.entity";
|
||||||
import { Hotel } from "@/database/entities/hotel.entity";
|
import { HotelSchedule } from "@/database/entities/hotel-schedule.entity";
|
||||||
import { PackageItinerary } from "@/database/entities/package-itinerary.entity";
|
import { PackageItinerary } from "@/database/entities/package-itinerary.entity";
|
||||||
import { Package } from "@/database/entities/package.entity";
|
import { Package } from "@/database/entities/package.entity";
|
||||||
import { TransportationClass } from "@/database/entities/transportation-class.entity";
|
import { TransportationClass } from "@/database/entities/transportation-class.entity";
|
||||||
@@ -43,21 +43,21 @@ export class PackageDetail {
|
|||||||
})
|
})
|
||||||
inboundFlight!: Rel<FlightSchedule>;
|
inboundFlight!: Rel<FlightSchedule>;
|
||||||
|
|
||||||
@ManyToMany(() => Hotel, undefined, {
|
@ManyToMany(() => HotelSchedule, undefined, {
|
||||||
owner: true,
|
owner: true,
|
||||||
cascade: [Cascade.REMOVE],
|
cascade: [Cascade.REMOVE],
|
||||||
})
|
})
|
||||||
tourHotels = new Collection<Hotel>(this);
|
tourHotels = new Collection<HotelSchedule>(this);
|
||||||
|
|
||||||
@ManyToOne(() => Hotel, {
|
@ManyToOne(() => HotelSchedule, {
|
||||||
cascade: [Cascade.REMOVE],
|
cascade: [Cascade.REMOVE],
|
||||||
})
|
})
|
||||||
makkahHotel!: Rel<Hotel>;
|
makkahHotel!: Rel<HotelSchedule>;
|
||||||
|
|
||||||
@ManyToOne(() => Hotel, {
|
@ManyToOne(() => HotelSchedule, {
|
||||||
cascade: [Cascade.REMOVE],
|
cascade: [Cascade.REMOVE],
|
||||||
})
|
})
|
||||||
madinahHotel!: Rel<Hotel>;
|
madinahHotel!: Rel<HotelSchedule>;
|
||||||
|
|
||||||
@ManyToOne(() => TransportationClass)
|
@ManyToOne(() => TransportationClass)
|
||||||
transportation!: Rel<TransportationClass>;
|
transportation!: Rel<TransportationClass>;
|
||||||
|
|||||||
@@ -1318,6 +1318,100 @@
|
|||||||
},
|
},
|
||||||
"nativeEnums": {}
|
"nativeEnums": {}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 30,
|
||||||
|
"mappedType": "string"
|
||||||
|
},
|
||||||
|
"hotel_id": {
|
||||||
|
"name": "hotel_id",
|
||||||
|
"type": "varchar(30)",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 30,
|
||||||
|
"mappedType": "string"
|
||||||
|
},
|
||||||
|
"check_in": {
|
||||||
|
"name": "check_in",
|
||||||
|
"type": "date",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 0,
|
||||||
|
"mappedType": "date"
|
||||||
|
},
|
||||||
|
"check_out": {
|
||||||
|
"name": "check_out",
|
||||||
|
"type": "date",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 0,
|
||||||
|
"mappedType": "date"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamptz",
|
||||||
|
"unsigned": false,
|
||||||
|
"autoincrement": false,
|
||||||
|
"primary": false,
|
||||||
|
"nullable": false,
|
||||||
|
"length": 6,
|
||||||
|
"mappedType": "datetime"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "hotel_schedule",
|
||||||
|
"schema": "public",
|
||||||
|
"indexes": [
|
||||||
|
{
|
||||||
|
"keyName": "hotel_schedule_pkey",
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"composite": false,
|
||||||
|
"constraint": true,
|
||||||
|
"primary": true,
|
||||||
|
"unique": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"checks": [],
|
||||||
|
"foreignKeys": {
|
||||||
|
"hotel_schedule_hotel_id_foreign": {
|
||||||
|
"constraintName": "hotel_schedule_hotel_id_foreign",
|
||||||
|
"columnNames": [
|
||||||
|
"hotel_id"
|
||||||
|
],
|
||||||
|
"localTableName": "public.hotel_schedule",
|
||||||
|
"referencedColumnNames": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"referencedTableName": "public.hotel",
|
||||||
|
"updateRule": "cascade"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nativeEnums": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": {
|
"id": {
|
||||||
@@ -2852,7 +2946,7 @@
|
|||||||
"referencedColumnNames": [
|
"referencedColumnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
],
|
||||||
"referencedTableName": "public.hotel",
|
"referencedTableName": "public.hotel_schedule",
|
||||||
"deleteRule": "cascade"
|
"deleteRule": "cascade"
|
||||||
},
|
},
|
||||||
"package_detail_madinah_hotel_id_foreign": {
|
"package_detail_madinah_hotel_id_foreign": {
|
||||||
@@ -2864,7 +2958,7 @@
|
|||||||
"referencedColumnNames": [
|
"referencedColumnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
],
|
||||||
"referencedTableName": "public.hotel",
|
"referencedTableName": "public.hotel_schedule",
|
||||||
"deleteRule": "cascade"
|
"deleteRule": "cascade"
|
||||||
},
|
},
|
||||||
"package_detail_transportation_id_foreign": {
|
"package_detail_transportation_id_foreign": {
|
||||||
@@ -2906,8 +3000,8 @@
|
|||||||
"length": 30,
|
"length": 30,
|
||||||
"mappedType": "string"
|
"mappedType": "string"
|
||||||
},
|
},
|
||||||
"hotel_id": {
|
"hotel_schedule_id": {
|
||||||
"name": "hotel_id",
|
"name": "hotel_schedule_id",
|
||||||
"type": "varchar(30)",
|
"type": "varchar(30)",
|
||||||
"unsigned": false,
|
"unsigned": false,
|
||||||
"autoincrement": false,
|
"autoincrement": false,
|
||||||
@@ -2924,7 +3018,7 @@
|
|||||||
"keyName": "package_detail_tour_hotels_pkey",
|
"keyName": "package_detail_tour_hotels_pkey",
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"package_detail_id",
|
"package_detail_id",
|
||||||
"hotel_id"
|
"hotel_schedule_id"
|
||||||
],
|
],
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"constraint": true,
|
"constraint": true,
|
||||||
@@ -2947,16 +3041,16 @@
|
|||||||
"deleteRule": "cascade",
|
"deleteRule": "cascade",
|
||||||
"updateRule": "cascade"
|
"updateRule": "cascade"
|
||||||
},
|
},
|
||||||
"package_detail_tour_hotels_hotel_id_foreign": {
|
"package_detail_tour_hotels_hotel_schedule_id_foreign": {
|
||||||
"constraintName": "package_detail_tour_hotels_hotel_id_foreign",
|
"constraintName": "package_detail_tour_hotels_hotel_schedule_id_foreign",
|
||||||
"columnNames": [
|
"columnNames": [
|
||||||
"hotel_id"
|
"hotel_schedule_id"
|
||||||
],
|
],
|
||||||
"localTableName": "public.package_detail_tour_hotels",
|
"localTableName": "public.package_detail_tour_hotels",
|
||||||
"referencedColumnNames": [
|
"referencedColumnNames": [
|
||||||
"id"
|
"id"
|
||||||
],
|
],
|
||||||
"referencedTableName": "public.hotel",
|
"referencedTableName": "public.hotel_schedule",
|
||||||
"deleteRule": "cascade",
|
"deleteRule": "cascade",
|
||||||
"updateRule": "cascade"
|
"updateRule": "cascade"
|
||||||
}
|
}
|
||||||
|
|||||||
107
src/database/migrations/Migration20251205022442.ts
Normal file
107
src/database/migrations/Migration20251205022442.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import { Migration } from "@mikro-orm/migrations";
|
||||||
|
|
||||||
|
export class Migration20251205022442 extends Migration {
|
||||||
|
override async up(): Promise<void> {
|
||||||
|
const knex = this.getKnex();
|
||||||
|
|
||||||
|
await knex.schema.alterTable("package_detail", (table) => {
|
||||||
|
table.dropColumns("makkah_hotel_id", "madinah_hotel_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.alterTable("package_detail_tour_hotels", (table) => {
|
||||||
|
table.dropColumn("hotel_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.createTable("hotel_schedule", (table) => {
|
||||||
|
// Columns
|
||||||
|
table.string("id", 30).notNullable();
|
||||||
|
table.string("hotel_id", 30).notNullable();
|
||||||
|
table.date("check_in").notNullable();
|
||||||
|
table.date("check_out").notNullable();
|
||||||
|
table.timestamp("created_at", { useTz: true }).notNullable();
|
||||||
|
table.timestamp("updated_at", { useTz: true }).notNullable();
|
||||||
|
// Constraints
|
||||||
|
table.primary(["id"], { constraintName: "hotel_schedule_pkey" });
|
||||||
|
table
|
||||||
|
.foreign("hotel_id", "hotel_schedule_hotel_id_foreign")
|
||||||
|
.references("hotel.id")
|
||||||
|
.onUpdate("NO ACTION")
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.alterTable("package_detail", (table) => {
|
||||||
|
table.string("makkah_hotel_id", 30).notNullable();
|
||||||
|
table.string("madinah_hotel_id", 30).notNullable();
|
||||||
|
table
|
||||||
|
.foreign("makkah_hotel_id", "package_detail_makkah_hotel_id_foreign")
|
||||||
|
.references("hotel_schedule.id")
|
||||||
|
.onUpdate("NO ACTION")
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
table
|
||||||
|
.foreign("madinah_hotel_id", "package_detail_madinah_hotel_id_foreign")
|
||||||
|
.references("hotel_schedule.id")
|
||||||
|
.onUpdate("NO ACTION")
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.alterTable("package_detail_tour_hotels", (table) => {
|
||||||
|
table.string("hotel_id", 30).notNullable();
|
||||||
|
table
|
||||||
|
.foreign("hotel_id", "package_detail_tour_hotels_hotel_id_foreign")
|
||||||
|
.references("hotel_schedule.id")
|
||||||
|
.onUpdate("NO ACTION")
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override async down(): Promise<void> {
|
||||||
|
const knex = this.getKnex();
|
||||||
|
|
||||||
|
await knex.schema.alterTable("package_detail_tour_hotels", (table) => {
|
||||||
|
table.dropForeign(
|
||||||
|
"hotel_id",
|
||||||
|
"package_detail_tour_hotels_hotel_id_foreign",
|
||||||
|
);
|
||||||
|
table.dropColumn("hotel_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.alterTable("package_detail", (table) => {
|
||||||
|
table.dropForeign(
|
||||||
|
"madinah_hotel_id",
|
||||||
|
"package_detail_madinah_hotel_id_foreign",
|
||||||
|
);
|
||||||
|
table.dropForeign(
|
||||||
|
"makkah_hotel_id",
|
||||||
|
"package_detail_makkah_hotel_id_foreign",
|
||||||
|
);
|
||||||
|
table.dropColumn("madinah_hotel_id");
|
||||||
|
table.dropColumn("makkah_hotel_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.dropTable("hotel_schedule");
|
||||||
|
|
||||||
|
await knex.schema.alterTable("package_detail_tour_hotels", (table) => {
|
||||||
|
table.string("hotel_id", 30).notNullable();
|
||||||
|
table
|
||||||
|
.foreign("hotel_id", "package_detail_tour_hotels_hotel_id_foreign")
|
||||||
|
.references("hotel.id")
|
||||||
|
.onUpdate("NO ACTION")
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.schema.alterTable("package_detail", (table) => {
|
||||||
|
table.string("makkah_hotel_id", 30).notNullable();
|
||||||
|
table.string("madinah_hotel_id", 30).notNullable();
|
||||||
|
table
|
||||||
|
.foreign("makkah_hotel_id", "package_detail_makkah_hotel_id_foreign")
|
||||||
|
.references("hotel.id")
|
||||||
|
.onUpdate("NO ACTION")
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
table
|
||||||
|
.foreign("madinah_hotel_id", "package_detail_madinah_hotel_id_foreign")
|
||||||
|
.references("hotel.id")
|
||||||
|
.onUpdate("NO ACTION")
|
||||||
|
.onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -465,7 +465,7 @@ export class PackageController extends Controller {
|
|||||||
const makkahHotel = await orm.em.findOne(
|
const makkahHotel = await orm.em.findOne(
|
||||||
Hotel,
|
Hotel,
|
||||||
{
|
{
|
||||||
id: body.makkah_hotel_id,
|
id: body.makkah_hotel.hotel_id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
populate: ["*"],
|
populate: ["*"],
|
||||||
@@ -487,7 +487,7 @@ export class PackageController extends Controller {
|
|||||||
const madinahHotel = await orm.em.findOne(
|
const madinahHotel = await orm.em.findOne(
|
||||||
Hotel,
|
Hotel,
|
||||||
{
|
{
|
||||||
id: body.madinah_hotel_id,
|
id: body.madinah_hotel.hotel_id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
populate: ["*"],
|
populate: ["*"],
|
||||||
@@ -671,8 +671,22 @@ export class PackageController extends Controller {
|
|||||||
tourFlight: tourFlightSchedule,
|
tourFlight: tourFlightSchedule,
|
||||||
outboundFlight: outboundFlightSchedule,
|
outboundFlight: outboundFlightSchedule,
|
||||||
inboundFlight: inboundFlightSchedule,
|
inboundFlight: inboundFlightSchedule,
|
||||||
makkahHotel: makkahHotel,
|
makkahHotel: {
|
||||||
madinahHotel: madinahHotel,
|
id: ulid(),
|
||||||
|
hotel: makkahHotel,
|
||||||
|
checkIn: body.makkah_hotel.check_in,
|
||||||
|
checkOut: body.makkah_hotel.check_out,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
|
madinahHotel: {
|
||||||
|
id: ulid(),
|
||||||
|
hotel: madinahHotel,
|
||||||
|
checkIn: body.madinah_hotel.check_in,
|
||||||
|
checkOut: body.madinah_hotel.check_out,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
transportation: transportationClass,
|
transportation: transportationClass,
|
||||||
quadPrice: body.quad_price,
|
quadPrice: body.quad_price,
|
||||||
quadDiscount: body.quad_discount,
|
quadDiscount: body.quad_discount,
|
||||||
@@ -687,22 +701,22 @@ export class PackageController extends Controller {
|
|||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const [index, tourHotelId] of (body.tour_hotel_ids ?? []).entries()) {
|
for (const [index, tourHotel] of (body.tour_hotels ?? []).entries()) {
|
||||||
const tourHotel = await orm.em.findOne(
|
const tourHotelEntity = await orm.em.findOne(
|
||||||
Hotel,
|
Hotel,
|
||||||
{
|
{
|
||||||
id: tourHotelId,
|
id: tourHotel.hotel_id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
populate: ["*"],
|
populate: ["*"],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (!tourHotel) {
|
if (!tourHotelEntity) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
data: null,
|
data: null,
|
||||||
errors: [
|
errors: [
|
||||||
{
|
{
|
||||||
path: `tour_hotel_ids.${index}`,
|
path: `tour_hotels.${index}.hotel_id`,
|
||||||
location: "body",
|
location: "body",
|
||||||
message: "Hotel not found.",
|
message: "Hotel not found.",
|
||||||
},
|
},
|
||||||
@@ -710,7 +724,14 @@ export class PackageController extends Controller {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
packageDetail.tourHotels.add(tourHotel);
|
packageDetail.tourHotels.add({
|
||||||
|
id: ulid(),
|
||||||
|
hotel: tourHotelEntity,
|
||||||
|
checkIn: tourHotel.check_in,
|
||||||
|
checkOut: tourHotel.check_out,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await orm.em.flush();
|
await orm.em.flush();
|
||||||
@@ -1029,7 +1050,7 @@ export class PackageController extends Controller {
|
|||||||
const makkahHotel = await orm.em.findOne(
|
const makkahHotel = await orm.em.findOne(
|
||||||
Hotel,
|
Hotel,
|
||||||
{
|
{
|
||||||
id: body.makkah_hotel_id,
|
id: body.makkah_hotel.hotel_id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
populate: ["*"],
|
populate: ["*"],
|
||||||
@@ -1051,7 +1072,7 @@ export class PackageController extends Controller {
|
|||||||
const madinahHotel = await orm.em.findOne(
|
const madinahHotel = await orm.em.findOne(
|
||||||
Hotel,
|
Hotel,
|
||||||
{
|
{
|
||||||
id: body.madinah_hotel_id,
|
id: body.madinah_hotel.hotel_id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
populate: ["*"],
|
populate: ["*"],
|
||||||
@@ -1258,8 +1279,18 @@ export class PackageController extends Controller {
|
|||||||
tourFlight: tourFlightSchedule,
|
tourFlight: tourFlightSchedule,
|
||||||
outboundFlight: outboundFlightSchedule,
|
outboundFlight: outboundFlightSchedule,
|
||||||
inboundFlight: inboundFlightSchedule,
|
inboundFlight: inboundFlightSchedule,
|
||||||
makkahHotel: makkahHotel,
|
makkahHotel: {
|
||||||
madinahHotel: madinahHotel,
|
hotel: makkahHotel,
|
||||||
|
checkIn: body.makkah_hotel.check_in,
|
||||||
|
checkOut: body.makkah_hotel.check_out,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
|
madinahHotel: {
|
||||||
|
hotel: madinahHotel,
|
||||||
|
checkIn: body.madinah_hotel.check_in,
|
||||||
|
checkOut: body.madinah_hotel.check_out,
|
||||||
|
updatedAt: new Date(),
|
||||||
|
},
|
||||||
transportation: transportationClass,
|
transportation: transportationClass,
|
||||||
quadPrice: body.quad_price,
|
quadPrice: body.quad_price,
|
||||||
quadDiscount: body.quad_discount,
|
quadDiscount: body.quad_discount,
|
||||||
@@ -1274,22 +1305,22 @@ export class PackageController extends Controller {
|
|||||||
});
|
});
|
||||||
|
|
||||||
packageDetail.tourHotels.set([]);
|
packageDetail.tourHotels.set([]);
|
||||||
for (const [index, tourHotelId] of (body.tour_hotel_ids ?? []).entries()) {
|
for (const [index, tourHotel] of (body.tour_hotels ?? []).entries()) {
|
||||||
const tourHotel = await orm.em.findOne(
|
const tourHotelEntity = await orm.em.findOne(
|
||||||
Hotel,
|
Hotel,
|
||||||
{
|
{
|
||||||
id: tourHotelId,
|
id: tourHotel.hotel_id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
populate: ["*"],
|
populate: ["*"],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (!tourHotel) {
|
if (!tourHotelEntity) {
|
||||||
return res.status(404).json({
|
return res.status(404).json({
|
||||||
data: null,
|
data: null,
|
||||||
errors: [
|
errors: [
|
||||||
{
|
{
|
||||||
path: `tour_hotel_ids.${index}`,
|
path: `tour_hotels.${index}.hotel_id`,
|
||||||
location: "body",
|
location: "body",
|
||||||
message: "Hotel not found.",
|
message: "Hotel not found.",
|
||||||
},
|
},
|
||||||
@@ -1297,7 +1328,14 @@ export class PackageController extends Controller {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
packageDetail.tourHotels.add(tourHotel);
|
packageDetail.tourHotels.add({
|
||||||
|
id: ulid(),
|
||||||
|
hotel: tourHotelEntity,
|
||||||
|
checkIn: tourHotel.check_in,
|
||||||
|
checkOut: tourHotel.check_out,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await orm.em.flush();
|
await orm.em.flush();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { FlightSchedule } from "@/database/entities/flight-schedule.entity";
|
import type { FlightSchedule } from "@/database/entities/flight-schedule.entity";
|
||||||
|
import type { HotelSchedule } from "@/database/entities/hotel-schedule.entity";
|
||||||
import type { PackageDetail } from "@/database/entities/package-detail.entity";
|
import type { PackageDetail } from "@/database/entities/package-detail.entity";
|
||||||
import type { PackageItineraryDay } from "@/database/entities/package-itinerary-day.entity";
|
import type { PackageItineraryDay } from "@/database/entities/package-itinerary-day.entity";
|
||||||
import type {
|
import type {
|
||||||
@@ -15,6 +16,7 @@ import type { FlightClassResponse } from "@/modules/flight/flight.types";
|
|||||||
import type { HotelMapper } from "@/modules/hotel/hotel.mapper";
|
import type { HotelMapper } from "@/modules/hotel/hotel.mapper";
|
||||||
import type {
|
import type {
|
||||||
PackageDetailResponse,
|
PackageDetailResponse,
|
||||||
|
PackageHotelResponse,
|
||||||
PackageItineraryDayResponse,
|
PackageItineraryDayResponse,
|
||||||
PackageItineraryResponse,
|
PackageItineraryResponse,
|
||||||
PackageItineraryWidgetResponse,
|
PackageItineraryWidgetResponse,
|
||||||
@@ -65,6 +67,14 @@ export class PackageMapper {
|
|||||||
return flightClassResponses;
|
return flightClassResponses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private mapHotelSchedule(hotelSchedule: HotelSchedule): PackageHotelResponse {
|
||||||
|
return {
|
||||||
|
hotel: this.hotelMapper.mapEntityToResponse(hotelSchedule.hotel),
|
||||||
|
check_in: dateFns.format(hotelSchedule.checkIn, "yyyy-MM-dd"),
|
||||||
|
check_out: dateFns.format(hotelSchedule.checkOut, "yyyy-MM-dd"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private mapItineraryWidget(
|
private mapItineraryWidget(
|
||||||
packageItineraryWidget: PackageItineraryWidget,
|
packageItineraryWidget: PackageItineraryWidget,
|
||||||
): PackageItineraryWidgetResponse {
|
): PackageItineraryWidgetResponse {
|
||||||
@@ -161,14 +171,10 @@ export class PackageMapper {
|
|||||||
outbound_flights: this.mapFlightSchedule(packageDetail.outboundFlight),
|
outbound_flights: this.mapFlightSchedule(packageDetail.outboundFlight),
|
||||||
inbound_flights: this.mapFlightSchedule(packageDetail.inboundFlight),
|
inbound_flights: this.mapFlightSchedule(packageDetail.inboundFlight),
|
||||||
tour_hotels: packageDetail.tourHotels.map(
|
tour_hotels: packageDetail.tourHotels.map(
|
||||||
this.hotelMapper.mapEntityToResponse,
|
this.mapHotelSchedule.bind(this),
|
||||||
),
|
|
||||||
makkah_hotel: this.hotelMapper.mapEntityToResponse(
|
|
||||||
packageDetail.makkahHotel,
|
|
||||||
),
|
|
||||||
madinah_hotel: this.hotelMapper.mapEntityToResponse(
|
|
||||||
packageDetail.madinahHotel,
|
|
||||||
),
|
),
|
||||||
|
makkah_hotel: this.mapHotelSchedule(packageDetail.makkahHotel),
|
||||||
|
madinah_hotel: this.mapHotelSchedule(packageDetail.madinahHotel),
|
||||||
transportation: this.transportationMapper.mapClassEntityToResponse(
|
transportation: this.transportationMapper.mapClassEntityToResponse(
|
||||||
packageDetail.transportation,
|
packageDetail.transportation,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -51,24 +51,45 @@ export const packageDetailRequestSchema = z.object({
|
|||||||
"Must be array.",
|
"Must be array.",
|
||||||
)
|
)
|
||||||
.nonempty("Must not empty."),
|
.nonempty("Must not empty."),
|
||||||
tour_hotel_ids: z
|
tour_hotels: z
|
||||||
.array(
|
.array(
|
||||||
z
|
z.object(
|
||||||
.ulid("Must be ulid string.")
|
{
|
||||||
.nonempty("Must not empty.")
|
hotel_id: z
|
||||||
.max(30, "Max 30 characters."),
|
.ulid("Must be ulid string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(30, "Max 30 characters."),
|
||||||
|
check_in: dateSchema,
|
||||||
|
check_out: dateSchema,
|
||||||
|
},
|
||||||
|
"Must be object.",
|
||||||
|
),
|
||||||
"Must be array.",
|
"Must be array.",
|
||||||
)
|
)
|
||||||
.nonempty("Must not empty.")
|
.nonempty("Must not empty.")
|
||||||
.nullable(),
|
.nullable(),
|
||||||
makkah_hotel_id: z
|
makkah_hotel: z.object(
|
||||||
.ulid("Must be ulid string.")
|
{
|
||||||
.nonempty("Must not empty.")
|
hotel_id: z
|
||||||
.max(30, "Max 30 characters."),
|
.ulid("Must be ulid string.")
|
||||||
madinah_hotel_id: z
|
.nonempty("Must not empty.")
|
||||||
.ulid("Must be ulid string.")
|
.max(30, "Max 30 characters."),
|
||||||
.nonempty("Must not empty.")
|
check_in: dateSchema,
|
||||||
.max(30, "Max 30 characters."),
|
check_out: dateSchema,
|
||||||
|
},
|
||||||
|
"Must be object.",
|
||||||
|
),
|
||||||
|
madinah_hotel: z.object(
|
||||||
|
{
|
||||||
|
hotel_id: z
|
||||||
|
.ulid("Must be ulid string.")
|
||||||
|
.nonempty("Must not empty.")
|
||||||
|
.max(30, "Max 30 characters."),
|
||||||
|
check_in: dateSchema,
|
||||||
|
check_out: dateSchema,
|
||||||
|
},
|
||||||
|
"Must be object.",
|
||||||
|
),
|
||||||
transportation_id: z
|
transportation_id: z
|
||||||
.ulid("Must be ulid string.")
|
.ulid("Must be ulid string.")
|
||||||
.nonempty("Must not empty.")
|
.nonempty("Must not empty.")
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ export type PackageConsultResponse = {
|
|||||||
session_code: string;
|
session_code: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PackageHotelResponse = {
|
||||||
|
hotel: HotelResponse;
|
||||||
|
check_in: string;
|
||||||
|
check_out: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type PackageItineraryWidgetResponse =
|
export type PackageItineraryWidgetResponse =
|
||||||
| {
|
| {
|
||||||
type: "transport";
|
type: "transport";
|
||||||
@@ -73,9 +79,9 @@ export type PackageDetailResponse = {
|
|||||||
tour_flights: FlightClassResponse[] | null;
|
tour_flights: FlightClassResponse[] | null;
|
||||||
outbound_flights: FlightClassResponse[];
|
outbound_flights: FlightClassResponse[];
|
||||||
inbound_flights: FlightClassResponse[];
|
inbound_flights: FlightClassResponse[];
|
||||||
tour_hotels: HotelResponse[] | null;
|
tour_hotels: PackageHotelResponse[] | null;
|
||||||
makkah_hotel: HotelResponse;
|
makkah_hotel: PackageHotelResponse;
|
||||||
madinah_hotel: HotelResponse;
|
madinah_hotel: PackageHotelResponse;
|
||||||
transportation: TransportationClassResponse;
|
transportation: TransportationClassResponse;
|
||||||
quad_price: number;
|
quad_price: number;
|
||||||
quad_discount: number;
|
quad_discount: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user