Auto commit: 2025-05-24T06:18:04.409Z
This commit is contained in:
parent
e93f945df3
commit
4f42c9d4ed
File diff suppressed because one or more lines are too long
@ -34,25 +34,6 @@ const config = {
|
||||
clientId: process.env.MS_CLIENT_ID || '',
|
||||
clientSecret: process.env.MS_CLIENT_SECRET || '',
|
||||
},
|
||||
amadeus: {
|
||||
clientId: process.env.AMADEUS_CLIENT_ID || 'YnlNGEWG0bMODXXFh59aWczdKy2Abr3l',
|
||||
clientSecret: process.env.AMADEUS_CLIENT_SECRET || 'YaSiX7mGOu3dhDz6',
|
||||
baseURL: 'https://test.api.amadeus.com',
|
||||
},
|
||||
|
||||
tap: {
|
||||
secretKey: process.env.TAP_SECRET_KEY || 'sk_test_XKokBfNWv6FIYuTMg5LPjhJ',
|
||||
publishableKey: process.env.TAP_PUBLISHABLE_KEY || 'pk_test_EtHFV4BuPQokJT6jiROls87Y',
|
||||
merchantId: process.env.TAP_MERCHANT_ID || '26374580',
|
||||
baseURL: 'https://api.tap.company',
|
||||
successUrl: process.env.TAP_SUCCESS_URL || 'https://flyaru.com/payment-success',
|
||||
failureUrl: process.env.TAP_FAILURE_URL || 'https://flyaru.com/payment-failed',
|
||||
webhookUrl: process.env.TAP_WEBHOOK_URL || 'https://flyaru.com/api/webhook',
|
||||
force3DSecure: true,
|
||||
capture: 'capture',
|
||||
refundWindowDays: 30,
|
||||
},
|
||||
|
||||
uploadDir: os.tmpdir(),
|
||||
email: {
|
||||
from: 'FlyAru-Powered by Arwa Travel Group <app@flatlogic.app>',
|
||||
|
||||
@ -20,6 +20,7 @@ module.exports = class ToursDBApi {
|
||||
price: data.price || null,
|
||||
start_date: data.start_date || null,
|
||||
end_date: data.end_date || null,
|
||||
image_url: data.image_url || null,
|
||||
importHash: data.importHash || null,
|
||||
createdById: currentUser.id,
|
||||
updatedById: currentUser.id,
|
||||
@ -51,6 +52,7 @@ module.exports = class ToursDBApi {
|
||||
price: item.price || null,
|
||||
start_date: item.start_date || null,
|
||||
end_date: item.end_date || null,
|
||||
image_url: item.image_url || null,
|
||||
importHash: item.importHash || null,
|
||||
createdById: currentUser.id,
|
||||
updatedById: currentUser.id,
|
||||
@ -86,6 +88,8 @@ module.exports = class ToursDBApi {
|
||||
|
||||
if (data.end_date !== undefined) updatePayload.end_date = data.end_date;
|
||||
|
||||
if (data.image_url !== undefined) updatePayload.image_url = data.image_url;
|
||||
|
||||
updatePayload.updatedById = currentUser.id;
|
||||
|
||||
await tours.update(updatePayload, { transaction });
|
||||
@ -171,6 +175,10 @@ module.exports = class ToursDBApi {
|
||||
transaction,
|
||||
});
|
||||
|
||||
output.cartitem_tour = await tours.getCartitem_tour({
|
||||
transaction,
|
||||
});
|
||||
|
||||
output.agency = await tours.getAgency({
|
||||
transaction,
|
||||
});
|
||||
@ -237,6 +245,13 @@ module.exports = class ToursDBApi {
|
||||
};
|
||||
}
|
||||
|
||||
if (filter.image_url) {
|
||||
where = {
|
||||
...where,
|
||||
[Op.and]: Utils.ilike('tours', 'image_url', filter.image_url),
|
||||
};
|
||||
}
|
||||
|
||||
if (filter.calendarStart && filter.calendarEnd) {
|
||||
where = {
|
||||
...where,
|
||||
|
||||
47
backend/src/db/migrations/1748067070073.js
Normal file
47
backend/src/db/migrations/1748067070073.js
Normal file
@ -0,0 +1,47 @@
|
||||
module.exports = {
|
||||
/**
|
||||
* @param {QueryInterface} queryInterface
|
||||
* @param {Sequelize} Sequelize
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async up(queryInterface, Sequelize) {
|
||||
/**
|
||||
* @type {Transaction}
|
||||
*/
|
||||
const transaction = await queryInterface.sequelize.transaction();
|
||||
try {
|
||||
await queryInterface.addColumn(
|
||||
'tours',
|
||||
'image_url',
|
||||
{
|
||||
type: Sequelize.DataTypes.TEXT,
|
||||
},
|
||||
{ transaction },
|
||||
);
|
||||
|
||||
await transaction.commit();
|
||||
} catch (err) {
|
||||
await transaction.rollback();
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {QueryInterface} queryInterface
|
||||
* @param {Sequelize} Sequelize
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async down(queryInterface, Sequelize) {
|
||||
/**
|
||||
* @type {Transaction}
|
||||
*/
|
||||
const transaction = await queryInterface.sequelize.transaction();
|
||||
try {
|
||||
await queryInterface.removeColumn('tours', 'image_url', { transaction });
|
||||
|
||||
await transaction.commit();
|
||||
} catch (err) {
|
||||
await transaction.rollback();
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
};
|
||||
36
backend/src/db/migrations/1748067295940.js
Normal file
36
backend/src/db/migrations/1748067295940.js
Normal file
@ -0,0 +1,36 @@
|
||||
module.exports = {
|
||||
/**
|
||||
* @param {QueryInterface} queryInterface
|
||||
* @param {Sequelize} Sequelize
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async up(queryInterface, Sequelize) {
|
||||
/**
|
||||
* @type {Transaction}
|
||||
*/
|
||||
const transaction = await queryInterface.sequelize.transaction();
|
||||
try {
|
||||
await transaction.commit();
|
||||
} catch (err) {
|
||||
await transaction.rollback();
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {QueryInterface} queryInterface
|
||||
* @param {Sequelize} Sequelize
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async down(queryInterface, Sequelize) {
|
||||
/**
|
||||
* @type {Transaction}
|
||||
*/
|
||||
const transaction = await queryInterface.sequelize.transaction();
|
||||
try {
|
||||
await transaction.commit();
|
||||
} catch (err) {
|
||||
await transaction.rollback();
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -34,6 +34,10 @@ module.exports = function (sequelize, DataTypes) {
|
||||
type: DataTypes.DATE,
|
||||
},
|
||||
|
||||
image_url: {
|
||||
type: DataTypes.TEXT,
|
||||
},
|
||||
|
||||
importHash: {
|
||||
type: DataTypes.STRING(255),
|
||||
allowNull: true,
|
||||
@ -58,6 +62,14 @@ module.exports = function (sequelize, DataTypes) {
|
||||
constraints: false,
|
||||
});
|
||||
|
||||
db.tours.hasMany(db.cartitem, {
|
||||
as: 'cartitem_tour',
|
||||
foreignKey: {
|
||||
name: 'tourId',
|
||||
},
|
||||
constraints: false,
|
||||
});
|
||||
|
||||
//end loop
|
||||
|
||||
db.tours.belongsTo(db.agencies, {
|
||||
|
||||
@ -11,6 +11,8 @@ const Agencies = db.agencies;
|
||||
|
||||
const Cart = db.cart;
|
||||
|
||||
const Cartitem = db.cartitem;
|
||||
|
||||
const AgentsData = [
|
||||
{
|
||||
name: 'Alice Green',
|
||||
@ -41,16 +43,6 @@ const AgentsData = [
|
||||
|
||||
// type code here for "relation_one" field
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Diana Blue',
|
||||
|
||||
commission_rate: 0.08,
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
},
|
||||
];
|
||||
|
||||
const BookingsData = [
|
||||
@ -73,7 +65,7 @@ const BookingsData = [
|
||||
|
||||
booking_date: new Date('2023-12-05T11:00:00Z'),
|
||||
|
||||
status: 'confirmed',
|
||||
status: 'pending',
|
||||
|
||||
// type code here for "relation_one" field
|
||||
},
|
||||
@ -85,19 +77,7 @@ const BookingsData = [
|
||||
|
||||
booking_date: new Date('2023-12-10T12:00:00Z'),
|
||||
|
||||
status: 'pending',
|
||||
|
||||
// type code here for "relation_one" field
|
||||
},
|
||||
|
||||
{
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
booking_date: new Date('2023-12-15T13:00:00Z'),
|
||||
|
||||
status: 'pending',
|
||||
status: 'confirmed',
|
||||
|
||||
// type code here for "relation_one" field
|
||||
},
|
||||
@ -118,6 +98,8 @@ const ToursData = [
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
image_url: 'Alfred Wegener',
|
||||
},
|
||||
|
||||
{
|
||||
@ -134,6 +116,8 @@ const ToursData = [
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
image_url: 'Konrad Lorenz',
|
||||
},
|
||||
|
||||
{
|
||||
@ -150,22 +134,8 @@ const ToursData = [
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
},
|
||||
|
||||
{
|
||||
title: 'Red Sea Diving Experience',
|
||||
|
||||
description: 'Dive into the vibrant underwater world of the Red Sea.',
|
||||
|
||||
price: 1000,
|
||||
|
||||
start_date: new Date('2024-04-01T09:00:00Z'),
|
||||
|
||||
end_date: new Date('2024-04-07T18:00:00Z'),
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
image_url: 'Alfred Kinsey',
|
||||
},
|
||||
];
|
||||
|
||||
@ -181,31 +151,63 @@ const AgenciesData = [
|
||||
{
|
||||
name: 'Adventure Seekers',
|
||||
},
|
||||
|
||||
{
|
||||
name: 'Cultural Journeys',
|
||||
},
|
||||
];
|
||||
|
||||
const CartData = [
|
||||
{
|
||||
// type code here for "relation_one" field
|
||||
// type code here for "relation_one" field
|
||||
// type code here for "relation_one" field
|
||||
},
|
||||
|
||||
{
|
||||
// type code here for "relation_one" field
|
||||
// type code here for "relation_one" field
|
||||
// type code here for "relation_one" field
|
||||
},
|
||||
|
||||
{
|
||||
// type code here for "relation_one" field
|
||||
// type code here for "relation_one" field
|
||||
// type code here for "relation_one" field
|
||||
},
|
||||
];
|
||||
|
||||
const CartitemData = [
|
||||
{
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
quantity: 7,
|
||||
|
||||
unitprice: 13.85,
|
||||
},
|
||||
|
||||
{
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
quantity: 7,
|
||||
|
||||
unitprice: 88.36,
|
||||
},
|
||||
|
||||
{
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
// type code here for "relation_one" field
|
||||
|
||||
quantity: 4,
|
||||
|
||||
unitprice: 36.29,
|
||||
},
|
||||
];
|
||||
|
||||
@ -244,17 +246,6 @@ async function associateUserWithAgency() {
|
||||
if (User2?.setAgency) {
|
||||
await User2.setAgency(relatedAgency2);
|
||||
}
|
||||
|
||||
const relatedAgency3 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const User3 = await Users.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 3,
|
||||
});
|
||||
if (User3?.setAgency) {
|
||||
await User3.setAgency(relatedAgency3);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateAgentWithAgency() {
|
||||
@ -290,17 +281,6 @@ async function associateAgentWithAgency() {
|
||||
if (Agent2?.setAgency) {
|
||||
await Agent2.setAgency(relatedAgency2);
|
||||
}
|
||||
|
||||
const relatedAgency3 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Agent3 = await Agents.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 3,
|
||||
});
|
||||
if (Agent3?.setAgency) {
|
||||
await Agent3.setAgency(relatedAgency3);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateAgentWithAgency() {
|
||||
@ -336,17 +316,6 @@ async function associateAgentWithAgency() {
|
||||
if (Agent2?.setAgency) {
|
||||
await Agent2.setAgency(relatedAgency2);
|
||||
}
|
||||
|
||||
const relatedAgency3 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Agent3 = await Agents.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 3,
|
||||
});
|
||||
if (Agent3?.setAgency) {
|
||||
await Agent3.setAgency(relatedAgency3);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateBookingWithTour() {
|
||||
@ -382,17 +351,6 @@ async function associateBookingWithTour() {
|
||||
if (Booking2?.setTour) {
|
||||
await Booking2.setTour(relatedTour2);
|
||||
}
|
||||
|
||||
const relatedTour3 = await Tours.findOne({
|
||||
offset: Math.floor(Math.random() * (await Tours.count())),
|
||||
});
|
||||
const Booking3 = await Bookings.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 3,
|
||||
});
|
||||
if (Booking3?.setTour) {
|
||||
await Booking3.setTour(relatedTour3);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateBookingWithCustomer() {
|
||||
@ -428,17 +386,6 @@ async function associateBookingWithCustomer() {
|
||||
if (Booking2?.setCustomer) {
|
||||
await Booking2.setCustomer(relatedCustomer2);
|
||||
}
|
||||
|
||||
const relatedCustomer3 = await Users.findOne({
|
||||
offset: Math.floor(Math.random() * (await Users.count())),
|
||||
});
|
||||
const Booking3 = await Bookings.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 3,
|
||||
});
|
||||
if (Booking3?.setCustomer) {
|
||||
await Booking3.setCustomer(relatedCustomer3);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateBookingWithAgency() {
|
||||
@ -474,17 +421,6 @@ async function associateBookingWithAgency() {
|
||||
if (Booking2?.setAgency) {
|
||||
await Booking2.setAgency(relatedAgency2);
|
||||
}
|
||||
|
||||
const relatedAgency3 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Booking3 = await Bookings.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 3,
|
||||
});
|
||||
if (Booking3?.setAgency) {
|
||||
await Booking3.setAgency(relatedAgency3);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateTourWithAgency() {
|
||||
@ -520,17 +456,6 @@ async function associateTourWithAgency() {
|
||||
if (Tour2?.setAgency) {
|
||||
await Tour2.setAgency(relatedAgency2);
|
||||
}
|
||||
|
||||
const relatedAgency3 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Tour3 = await Tours.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 3,
|
||||
});
|
||||
if (Tour3?.setAgency) {
|
||||
await Tour3.setAgency(relatedAgency3);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateTourWithAgency() {
|
||||
@ -566,17 +491,6 @@ async function associateTourWithAgency() {
|
||||
if (Tour2?.setAgency) {
|
||||
await Tour2.setAgency(relatedAgency2);
|
||||
}
|
||||
|
||||
const relatedAgency3 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Tour3 = await Tours.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 3,
|
||||
});
|
||||
if (Tour3?.setAgency) {
|
||||
await Tour3.setAgency(relatedAgency3);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateCartWithAgency() {
|
||||
@ -612,17 +526,6 @@ async function associateCartWithAgency() {
|
||||
if (Cart2?.setAgency) {
|
||||
await Cart2.setAgency(relatedAgency2);
|
||||
}
|
||||
|
||||
const relatedAgency3 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Cart3 = await Cart.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 3,
|
||||
});
|
||||
if (Cart3?.setAgency) {
|
||||
await Cart3.setAgency(relatedAgency3);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateCartWithUser() {
|
||||
@ -658,16 +561,145 @@ async function associateCartWithUser() {
|
||||
if (Cart2?.setUser) {
|
||||
await Cart2.setUser(relatedUser2);
|
||||
}
|
||||
}
|
||||
|
||||
const relatedUser3 = await Users.findOne({
|
||||
offset: Math.floor(Math.random() * (await Users.count())),
|
||||
async function associateCartWithAgency() {
|
||||
const relatedAgency0 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Cart3 = await Cart.findOne({
|
||||
const Cart0 = await Cart.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 3,
|
||||
offset: 0,
|
||||
});
|
||||
if (Cart3?.setUser) {
|
||||
await Cart3.setUser(relatedUser3);
|
||||
if (Cart0?.setAgency) {
|
||||
await Cart0.setAgency(relatedAgency0);
|
||||
}
|
||||
|
||||
const relatedAgency1 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Cart1 = await Cart.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 1,
|
||||
});
|
||||
if (Cart1?.setAgency) {
|
||||
await Cart1.setAgency(relatedAgency1);
|
||||
}
|
||||
|
||||
const relatedAgency2 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Cart2 = await Cart.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 2,
|
||||
});
|
||||
if (Cart2?.setAgency) {
|
||||
await Cart2.setAgency(relatedAgency2);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateCartitemWithAgency() {
|
||||
const relatedAgency0 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Cartitem0 = await Cartitem.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 0,
|
||||
});
|
||||
if (Cartitem0?.setAgency) {
|
||||
await Cartitem0.setAgency(relatedAgency0);
|
||||
}
|
||||
|
||||
const relatedAgency1 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Cartitem1 = await Cartitem.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 1,
|
||||
});
|
||||
if (Cartitem1?.setAgency) {
|
||||
await Cartitem1.setAgency(relatedAgency1);
|
||||
}
|
||||
|
||||
const relatedAgency2 = await Agencies.findOne({
|
||||
offset: Math.floor(Math.random() * (await Agencies.count())),
|
||||
});
|
||||
const Cartitem2 = await Cartitem.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 2,
|
||||
});
|
||||
if (Cartitem2?.setAgency) {
|
||||
await Cartitem2.setAgency(relatedAgency2);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateCartitemWithCart() {
|
||||
const relatedCart0 = await Cart.findOne({
|
||||
offset: Math.floor(Math.random() * (await Cart.count())),
|
||||
});
|
||||
const Cartitem0 = await Cartitem.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 0,
|
||||
});
|
||||
if (Cartitem0?.setCart) {
|
||||
await Cartitem0.setCart(relatedCart0);
|
||||
}
|
||||
|
||||
const relatedCart1 = await Cart.findOne({
|
||||
offset: Math.floor(Math.random() * (await Cart.count())),
|
||||
});
|
||||
const Cartitem1 = await Cartitem.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 1,
|
||||
});
|
||||
if (Cartitem1?.setCart) {
|
||||
await Cartitem1.setCart(relatedCart1);
|
||||
}
|
||||
|
||||
const relatedCart2 = await Cart.findOne({
|
||||
offset: Math.floor(Math.random() * (await Cart.count())),
|
||||
});
|
||||
const Cartitem2 = await Cartitem.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 2,
|
||||
});
|
||||
if (Cartitem2?.setCart) {
|
||||
await Cartitem2.setCart(relatedCart2);
|
||||
}
|
||||
}
|
||||
|
||||
async function associateCartitemWithTour() {
|
||||
const relatedTour0 = await Tours.findOne({
|
||||
offset: Math.floor(Math.random() * (await Tours.count())),
|
||||
});
|
||||
const Cartitem0 = await Cartitem.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 0,
|
||||
});
|
||||
if (Cartitem0?.setTour) {
|
||||
await Cartitem0.setTour(relatedTour0);
|
||||
}
|
||||
|
||||
const relatedTour1 = await Tours.findOne({
|
||||
offset: Math.floor(Math.random() * (await Tours.count())),
|
||||
});
|
||||
const Cartitem1 = await Cartitem.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 1,
|
||||
});
|
||||
if (Cartitem1?.setTour) {
|
||||
await Cartitem1.setTour(relatedTour1);
|
||||
}
|
||||
|
||||
const relatedTour2 = await Tours.findOne({
|
||||
offset: Math.floor(Math.random() * (await Tours.count())),
|
||||
});
|
||||
const Cartitem2 = await Cartitem.findOne({
|
||||
order: [['id', 'ASC']],
|
||||
offset: 2,
|
||||
});
|
||||
if (Cartitem2?.setTour) {
|
||||
await Cartitem2.setTour(relatedTour2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -683,6 +715,8 @@ module.exports = {
|
||||
|
||||
await Cart.bulkCreate(CartData);
|
||||
|
||||
await Cartitem.bulkCreate(CartitemData);
|
||||
|
||||
await Promise.all([
|
||||
// Similar logic for "relation_many"
|
||||
|
||||
@ -705,6 +739,14 @@ module.exports = {
|
||||
await associateCartWithAgency(),
|
||||
|
||||
await associateCartWithUser(),
|
||||
|
||||
await associateCartWithAgency(),
|
||||
|
||||
await associateCartitemWithAgency(),
|
||||
|
||||
await associateCartitemWithCart(),
|
||||
|
||||
await associateCartitemWithTour(),
|
||||
]);
|
||||
},
|
||||
|
||||
@ -718,5 +760,7 @@ module.exports = {
|
||||
await queryInterface.bulkDelete('agencies', null, {});
|
||||
|
||||
await queryInterface.bulkDelete('cart', null, {});
|
||||
|
||||
await queryInterface.bulkDelete('cartitem', null, {});
|
||||
},
|
||||
};
|
||||
|
||||
75
backend/src/db/seeders/20250101000000-add-tour-packages.js
Normal file
75
backend/src/db/seeders/20250101000000-add-tour-packages.js
Normal file
@ -0,0 +1,75 @@
|
||||
'use strict';
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
module.exports = {
|
||||
up: async (queryInterface, Sequelize) => {
|
||||
await queryInterface.bulkInsert('tours', [
|
||||
{
|
||||
id: uuidv4(),
|
||||
title: 'Discover the Mysteries of Thailand',
|
||||
description: '2 nights in Krabi; 3 nights in Phuket; half-day tour of the Emerald Temple & waterfall; 7-Islands long-tail boat cruise with sunset dinner; half-day Phuket city tour with Big Buddha; Phi Phi Islands Maya Bay & Khai speedboat tour with lunch; all transfers via private boat.',
|
||||
price: 1881,
|
||||
start_date: null,
|
||||
end_date: null,
|
||||
image_url: 'https://www.arwatravelksa.com/images/pac2.jpeg',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: uuidv4(),
|
||||
title: 'Family Adventures in Thailand',
|
||||
description: 'Discover hidden gems, pristine beaches and vibrant cities while experiencing rich culture and hospitality in the Land of Smiles—designed for 2 adults + 1 child.',
|
||||
price: 2600,
|
||||
start_date: null,
|
||||
end_date: null,
|
||||
image_url: 'https://www.arwatravelksa.com/images/486033692_960427122968372_1468632099997282977_n.jpg',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: uuidv4(),
|
||||
title: 'Turkey Highlights: Trabzon & Istanbul',
|
||||
description: 'Cruise dinner in Istanbul; Princess Island tour; full-day Uzungöl & tea-factory visit; explore the heart of Trabzon.',
|
||||
price: 2850,
|
||||
start_date: null,
|
||||
end_date: null,
|
||||
image_url: 'https://www.arwatravelksa.com/images/pac5.jpeg',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: uuidv4(),
|
||||
title: 'Turkey – Trabzon & Istanbul (English Version)',
|
||||
description: 'Cruise dinner in Istanbul; Princess Island; full-day Uzungöl tour with tea factory; Heart of Trabzon.',
|
||||
price: null,
|
||||
start_date: null,
|
||||
end_date: null,
|
||||
image_url: 'https://www.arwatravelksa.com/images/pac3.jpeg',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: uuidv4(),
|
||||
title: 'Azerbaijan Explorer',
|
||||
description: 'Join us for an exciting trip to Qafqaz and Gabala; includes 4-star hotel, daily breakfast, one guided tour and all transport.',
|
||||
price: null,
|
||||
start_date: null,
|
||||
end_date: null,
|
||||
image_url: 'https://www.arwatravelksa.com/images/pac4.jpeg',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
}
|
||||
], {});
|
||||
},
|
||||
down: async (queryInterface, Sequelize) => {
|
||||
await queryInterface.bulkDelete('tours', {
|
||||
title: [
|
||||
'Discover the Mysteries of Thailand',
|
||||
'Family Adventures in Thailand',
|
||||
'Turkey Highlights: Trabzon & Istanbul',
|
||||
'Turkey – Trabzon & Istanbul (English Version)',
|
||||
'Azerbaijan Explorer'
|
||||
]
|
||||
}, {});
|
||||
}
|
||||
};
|
||||
@ -28,6 +28,9 @@ router.use(checkCrudPermissions('tours'));
|
||||
* description:
|
||||
* type: string
|
||||
* default: description
|
||||
* image_url:
|
||||
* type: string
|
||||
* default: image_url
|
||||
|
||||
* price:
|
||||
* type: integer
|
||||
@ -316,6 +319,7 @@ router.get(
|
||||
'id',
|
||||
'title',
|
||||
'description',
|
||||
'image_url',
|
||||
|
||||
'price',
|
||||
'start_date',
|
||||
|
||||
@ -45,7 +45,7 @@ module.exports = class SearchService {
|
||||
|
||||
agents: ['name'],
|
||||
|
||||
tours: ['title', 'description'],
|
||||
tours: ['title', 'description', 'image_url'],
|
||||
|
||||
agencies: ['name'],
|
||||
};
|
||||
@ -53,6 +53,8 @@ module.exports = class SearchService {
|
||||
agents: ['commission_rate'],
|
||||
|
||||
tours: ['price'],
|
||||
|
||||
cartitem: ['quantity', 'unitprice'],
|
||||
};
|
||||
|
||||
let allFoundRecords = [];
|
||||
|
||||
@ -135,6 +135,17 @@ const CardTours = ({
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
<div className='flex justify-between gap-x-4 py-3'>
|
||||
<dt className=' text-gray-500 dark:text-dark-600'>
|
||||
Image url
|
||||
</dt>
|
||||
<dd className='flex items-start gap-x-2'>
|
||||
<div className='font-medium line-clamp-4'>
|
||||
{item.image_url}
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</li>
|
||||
))}
|
||||
|
||||
@ -88,6 +88,11 @@ const ListTours = ({
|
||||
{dataFormatter.agenciesOneListFormatter(item.agency)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className={'flex-1 px-3'}>
|
||||
<p className={'text-xs text-gray-500 '}>Image url</p>
|
||||
<p className={'line-clamp-2'}>{item.image_url}</p>
|
||||
</div>
|
||||
</Link>
|
||||
<ListActionsPopover
|
||||
onDelete={onDelete}
|
||||
|
||||
@ -128,6 +128,18 @@ export const loadColumns = async (
|
||||
params?.value?.id ?? params?.value,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'image_url',
|
||||
headerName: 'Image url',
|
||||
flex: 1,
|
||||
minWidth: 120,
|
||||
filterable: false,
|
||||
headerClassName: 'datagrid--header',
|
||||
cellClassName: 'datagrid--cell',
|
||||
|
||||
editable: hasUpdatePermission,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'actions',
|
||||
type: 'actions',
|
||||
|
||||
@ -19,7 +19,7 @@ export default function WebSiteFooter({ projectName }: WebSiteFooterProps) {
|
||||
|
||||
const style = FooterStyle.WITH_PAGES;
|
||||
|
||||
const design = FooterDesigns.DEFAULT_DESIGN;
|
||||
const design = FooterDesigns.DESIGN_DIVERSITY;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@ -17,9 +17,9 @@ export default function WebSiteHeader({ projectName }: WebSiteHeaderProps) {
|
||||
const websiteHeder = useAppSelector((state) => state.style.websiteHeder);
|
||||
const borders = useAppSelector((state) => state.style.borders);
|
||||
|
||||
const style = HeaderStyle.PAGES_LEFT;
|
||||
const style = HeaderStyle.PAGES_RIGHT;
|
||||
|
||||
const design = HeaderDesigns.DESIGN_DIVERSITY;
|
||||
const design = HeaderDesigns.DEFAULT_DESIGN;
|
||||
return (
|
||||
<header id='websiteHeader' className='overflow-hidden'>
|
||||
<div
|
||||
|
||||
112
frontend/src/menuAside.ts.temp
Normal file
112
frontend/src/menuAside.ts.temp
Normal file
@ -0,0 +1,112 @@
|
||||
import * as icon from '@mdi/js';
|
||||
import { MenuAsideItem } from './interfaces';
|
||||
|
||||
const menuAside: MenuAsideItem[] = [
|
||||
{
|
||||
href: '/dashboard',
|
||||
icon: icon.mdiViewDashboardOutline,
|
||||
label: 'Dashboard',
|
||||
},
|
||||
|
||||
{
|
||||
href: '/users/users-list',
|
||||
label: 'Users',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon: icon.mdiAccountGroup ?? icon.mdiTable,
|
||||
permissions: 'READ_USERS',
|
||||
},
|
||||
{
|
||||
href: '/agents/agents-list',
|
||||
label: 'Agents',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon:
|
||||
'mdiAccountTie' in icon
|
||||
? icon['mdiAccountTie' as keyof typeof icon]
|
||||
: icon.mdiTable ?? icon.mdiTable,
|
||||
permissions: 'READ_AGENTS',
|
||||
},
|
||||
{
|
||||
href: '/bookings/bookings-list',
|
||||
label: 'Bookings',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon:
|
||||
'mdiCalendarCheck' in icon
|
||||
? icon['mdiCalendarCheck' as keyof typeof icon]
|
||||
: icon.mdiTable ?? icon.mdiTable,
|
||||
permissions: 'READ_BOOKINGS',
|
||||
},
|
||||
{
|
||||
href: '/tours/tours-list',
|
||||
label: 'Tours',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon:
|
||||
'mdiMapMarker' in icon
|
||||
? icon['mdiMapMarker' as keyof typeof icon]
|
||||
: icon.mdiTable ?? icon.mdiTable,
|
||||
|
||||
{
|
||||
href: '/flights-search',
|
||||
label: 'Flights',
|
||||
icon: icon.mdiAirplane,
|
||||
},
|
||||
|
||||
permissions: 'READ_TOURS',
|
||||
},
|
||||
{
|
||||
href: '/roles/roles-list',
|
||||
label: 'Roles',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon: icon.mdiShieldAccountVariantOutline ?? icon.mdiTable,
|
||||
permissions: 'READ_ROLES',
|
||||
},
|
||||
{
|
||||
href: '/permissions/permissions-list',
|
||||
label: 'Permissions',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon: icon.mdiShieldAccountOutline ?? icon.mdiTable,
|
||||
permissions: 'READ_PERMISSIONS',
|
||||
},
|
||||
{
|
||||
href: '/agencies/agencies-list',
|
||||
label: 'Agencies',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon: icon.mdiTable ?? icon.mdiTable,
|
||||
permissions: 'READ_AGENCIES',
|
||||
},
|
||||
{
|
||||
href: '/cart/cart-list',
|
||||
label: 'Cart',
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
icon: icon.mdiTable ?? icon.mdiTable,
|
||||
permissions: 'READ_CART',
|
||||
},
|
||||
{
|
||||
href: '/profile',
|
||||
label: 'Profile',
|
||||
icon: icon.mdiAccountCircle,
|
||||
},
|
||||
|
||||
{
|
||||
href: '/home',
|
||||
label: 'Home page',
|
||||
icon: icon.mdiHome,
|
||||
withDevider: true,
|
||||
},
|
||||
{
|
||||
href: '/api-docs',
|
||||
target: '_blank',
|
||||
label: 'Swagger API',
|
||||
icon: icon.mdiFileCode,
|
||||
permissions: 'READ_API_DOCS',
|
||||
},
|
||||
];
|
||||
|
||||
export default menuAside;
|
||||
@ -258,6 +258,8 @@ const AgenciesView = () => {
|
||||
<th>StartDate</th>
|
||||
|
||||
<th>EndDate</th>
|
||||
|
||||
<th>Image url</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -281,6 +283,8 @@ const AgenciesView = () => {
|
||||
<td data-label='end_date'>
|
||||
{dataFormatter.dateTimeFormatter(item.end_date)}
|
||||
</td>
|
||||
|
||||
<td data-label='image_url'>{item.image_url}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@ -309,6 +313,8 @@ const AgenciesView = () => {
|
||||
<th>StartDate</th>
|
||||
|
||||
<th>EndDate</th>
|
||||
|
||||
<th>Image url</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -332,6 +338,8 @@ const AgenciesView = () => {
|
||||
<td data-label='end_date'>
|
||||
{dataFormatter.dateTimeFormatter(item.end_date)}
|
||||
</td>
|
||||
|
||||
<td data-label='image_url'>{item.image_url}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@ -374,6 +382,78 @@ const AgenciesView = () => {
|
||||
</CardBox>
|
||||
</>
|
||||
|
||||
<>
|
||||
<p className={'block font-bold mb-2'}>Cart Agency</p>
|
||||
<CardBox
|
||||
className='mb-6 border border-gray-300 rounded overflow-hidden'
|
||||
hasTable
|
||||
>
|
||||
<div className='overflow-x-auto'>
|
||||
<table>
|
||||
<thead>
|
||||
<tr></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{agencies.cart_agency &&
|
||||
Array.isArray(agencies.cart_agency) &&
|
||||
agencies.cart_agency.map((item: any) => (
|
||||
<tr
|
||||
key={item.id}
|
||||
onClick={() =>
|
||||
router.push(`/cart/cart-view/?id=${item.id}`)
|
||||
}
|
||||
></tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{!agencies?.cart_agency?.length && (
|
||||
<div className={'text-center py-4'}>No data</div>
|
||||
)}
|
||||
</CardBox>
|
||||
</>
|
||||
|
||||
<>
|
||||
<p className={'block font-bold mb-2'}>Cartitem agencies</p>
|
||||
<CardBox
|
||||
className='mb-6 border border-gray-300 rounded overflow-hidden'
|
||||
hasTable
|
||||
>
|
||||
<div className='overflow-x-auto'>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Quantity</th>
|
||||
|
||||
<th>Unitprice</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{agencies.cartitem_agencies &&
|
||||
Array.isArray(agencies.cartitem_agencies) &&
|
||||
agencies.cartitem_agencies.map((item: any) => (
|
||||
<tr
|
||||
key={item.id}
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/cartitem/cartitem-view/?id=${item.id}`,
|
||||
)
|
||||
}
|
||||
>
|
||||
<td data-label='quantity'>{item.quantity}</td>
|
||||
|
||||
<td data-label='unitprice'>{item.unitprice}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{!agencies?.cartitem_agencies?.length && (
|
||||
<div className={'text-center py-4'}>No data</div>
|
||||
)}
|
||||
</CardBox>
|
||||
</>
|
||||
|
||||
<BaseDivider />
|
||||
|
||||
<BaseButton
|
||||
|
||||
@ -51,6 +51,8 @@ const EditTours = () => {
|
||||
agency: null,
|
||||
|
||||
agencies: null,
|
||||
|
||||
image_url: '',
|
||||
};
|
||||
const [initialValues, setInitialValues] = useState(initVals);
|
||||
|
||||
@ -181,6 +183,10 @@ const EditTours = () => {
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
<FormField label='Image url'>
|
||||
<Field name='image_url' placeholder='Image url' />
|
||||
</FormField>
|
||||
|
||||
<BaseDivider />
|
||||
<BaseButtons>
|
||||
<BaseButton type='submit' color='info' label='Submit' />
|
||||
|
||||
@ -51,6 +51,8 @@ const EditToursPage = () => {
|
||||
agency: null,
|
||||
|
||||
agencies: null,
|
||||
|
||||
image_url: '',
|
||||
};
|
||||
const [initialValues, setInitialValues] = useState(initVals);
|
||||
|
||||
@ -179,6 +181,10 @@ const EditToursPage = () => {
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
<FormField label='Image url'>
|
||||
<Field name='image_url' placeholder='Image url' />
|
||||
</FormField>
|
||||
|
||||
<BaseDivider />
|
||||
<BaseButtons>
|
||||
<BaseButton type='submit' color='info' label='Submit' />
|
||||
|
||||
@ -31,6 +31,7 @@ const ToursTablesPage = () => {
|
||||
const [filters] = useState([
|
||||
{ label: 'TourTitle', title: 'title' },
|
||||
{ label: 'Description', title: 'description' },
|
||||
{ label: 'Image url', title: 'image_url' },
|
||||
|
||||
{ label: 'Price', title: 'price', number: 'true' },
|
||||
{ label: 'StartDate', title: 'start_date', date: 'true' },
|
||||
|
||||
@ -46,6 +46,8 @@ const initialValues = {
|
||||
agency: '',
|
||||
|
||||
agencies: '',
|
||||
|
||||
image_url: '',
|
||||
};
|
||||
|
||||
const ToursNew = () => {
|
||||
@ -139,6 +141,10 @@ const ToursNew = () => {
|
||||
></Field>
|
||||
</FormField>
|
||||
|
||||
<FormField label='Image url'>
|
||||
<Field name='image_url' placeholder='Image url' />
|
||||
</FormField>
|
||||
|
||||
<BaseDivider />
|
||||
<BaseButtons>
|
||||
<BaseButton type='submit' color='info' label='Submit' />
|
||||
|
||||
@ -31,6 +31,7 @@ const ToursTablesPage = () => {
|
||||
const [filters] = useState([
|
||||
{ label: 'TourTitle', title: 'title' },
|
||||
{ label: 'Description', title: 'description' },
|
||||
{ label: 'Image url', title: 'image_url' },
|
||||
|
||||
{ label: 'Price', title: 'price', number: 'true' },
|
||||
{ label: 'StartDate', title: 'start_date', date: 'true' },
|
||||
|
||||
@ -125,6 +125,11 @@ const ToursView = () => {
|
||||
<p>{tours?.agencies?.name ?? 'No data'}</p>
|
||||
</div>
|
||||
|
||||
<div className={'mb-4'}>
|
||||
<p className={'block font-bold mb-2'}>Image url</p>
|
||||
<p>{tours?.image_url}</p>
|
||||
</div>
|
||||
|
||||
<>
|
||||
<p className={'block font-bold mb-2'}>Bookings Tour</p>
|
||||
<CardBox
|
||||
@ -168,6 +173,47 @@ const ToursView = () => {
|
||||
</CardBox>
|
||||
</>
|
||||
|
||||
<>
|
||||
<p className={'block font-bold mb-2'}>Cartitem Tour</p>
|
||||
<CardBox
|
||||
className='mb-6 border border-gray-300 rounded overflow-hidden'
|
||||
hasTable
|
||||
>
|
||||
<div className='overflow-x-auto'>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Quantity</th>
|
||||
|
||||
<th>Unitprice</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{tours.cartitem_tour &&
|
||||
Array.isArray(tours.cartitem_tour) &&
|
||||
tours.cartitem_tour.map((item: any) => (
|
||||
<tr
|
||||
key={item.id}
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`/cartitem/cartitem-view/?id=${item.id}`,
|
||||
)
|
||||
}
|
||||
>
|
||||
<td data-label='quantity'>{item.quantity}</td>
|
||||
|
||||
<td data-label='unitprice'>{item.unitprice}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{!tours?.cartitem_tour?.length && (
|
||||
<div className={'text-center py-4'}>No data</div>
|
||||
)}
|
||||
</CardBox>
|
||||
</>
|
||||
|
||||
<BaseDivider />
|
||||
|
||||
<BaseButton
|
||||
|
||||
@ -142,7 +142,7 @@ export default function WebSite() {
|
||||
<FeaturesSection
|
||||
projectName={'FlyAru-Powered by Arwa Travel Group'}
|
||||
image={['Iconic travel destinations collage']}
|
||||
withBg={1}
|
||||
withBg={0}
|
||||
features={features_points}
|
||||
mainText={`Explore ${projectName} Features`}
|
||||
subTitle={`Discover the unique features of ${projectName} that make your travel planning seamless and enjoyable.`}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user