You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
308 lines
13 KiB
JavaScript
308 lines
13 KiB
JavaScript
const db = require('../config/db');
|
|
const initModels = require('./../models/init-models');
|
|
const { AvailableAccommodationIds, AccommodationsDetails, Availability } = require('../vendor/heytrip');
|
|
const { isEmpty } = require('../utils/commons');
|
|
const { resolveDetails, resolveRatePlans } = require('../helper/heytripDataHelper');
|
|
const { DEFAULT_LGC, LGC_MAPPED } = require('../config/constants');
|
|
|
|
const { sequelize: Sequelize, Op } = db;
|
|
|
|
const models = initModels(Sequelize);
|
|
|
|
const Country = models.countryModel;
|
|
const City = models.cityModel;
|
|
|
|
const HeytripIds = models.heytripIdsModel;
|
|
const Hotelinfo = models.hotelinfoModel;
|
|
const Hotelinfo2 = models.hotelinfo2Model;
|
|
const Rooms = models.roomsModel;
|
|
const Facility = models.facilityModel;
|
|
const Images = models.imagesModel;
|
|
const Informations = models.informationsModel;
|
|
const Reviews = models.reviewsModel;
|
|
const ReviewsSummaries = models.reviewsSummariesModel;
|
|
const Locations = models.locationsModel;
|
|
// const CacheAvailability = models.cacheAvailabilityModel;
|
|
|
|
// HeytripIds.hasMany(Hotelinfo, {
|
|
// foreignKey: 'hotel_id',
|
|
// onDelete: 'NO ACTION',
|
|
// onUpdate: 'NO ACTION',
|
|
// });
|
|
// Hotelinfo.belongsTo(HeytripIds, { as: 'aid', foreignKey: 'hotel_id', onDelete: 'NO ACTION', onUpdate: 'NO ACTION' });
|
|
// Hotelinfo.hasMany(Rooms, { sourceKey: 'hotel_id', foreignKey: 'hotel_id', onDelete: 'NO ACTION', onUpdate: 'NO ACTION' });
|
|
// Rooms.belongsTo(Hotelinfo, { targetKey: 'hotel_id', foreignKey: 'hotel_id', onDelete: 'NO ACTION', onUpdate: 'NO ACTION', });
|
|
Hotelinfo.hasMany(Hotelinfo2, { as: 'lgc_info', sourceKey: 'hotel_id', foreignKey: 'hotel_id', onDelete: 'NO ACTION', onUpdate: 'NO ACTION' });
|
|
Hotelinfo.hasMany(City, { as: 'city', sourceKey: 'city_id', foreignKey: 'id', onDelete: 'NO ACTION', onUpdate: 'NO ACTION', }); // 多语种, 所以实际是 hasMany , 用 hasOne 要指定 lgc= 1 或者2
|
|
Hotelinfo.hasMany(Country, { as: 'country', sourceKey: 'country_code', foreignKey: 'id', onDelete: 'NO ACTION', onUpdate: 'NO ACTION', }); // 多语种, 所以实际是 hasMany , 用 hasOne 要指定 lgc= 1 或者2
|
|
// Hotelinfo2.belongsTo(Hotelinfo, { targetKey: 'hotel_id', foreignKey: 'hotel_id', onDelete: 'NO ACTION', onUpdate: 'NO ACTION', });
|
|
|
|
class Heytrip {
|
|
/**
|
|
* 搜索酒店
|
|
*/
|
|
hotelSearch = async (keyword, options) => {
|
|
const keywordSplit = keyword.split(' ');
|
|
const keywordWhere = (field) => keywordSplit.map((word) => Sequelize.where(Sequelize.fn('instr', Sequelize.col(field), word), { [Op.gt]: 0 }));
|
|
// 'hotelinfo.address'
|
|
const keywordSearch = ['hotelinfo.hotel_name', ].map((field) => ({ [Op.and]: keywordWhere(field) }));
|
|
const keywordOrder = ['hotelinfo.hotel_name',].reduce((ro, field) => ro.concat(keywordSplit.map((word) => Sequelize.fn('instr', Sequelize.col(field), word))), []);
|
|
|
|
// const keywordSearchCount = ['hi2_hotel_name', 'hi2_address'].map((field) => ({ [Op.and]: keywordWhere(field) }));
|
|
// const countRows = await Hotelinfo2.count({
|
|
// where: {
|
|
// [Op.or]: keywordSearchCount,
|
|
// },
|
|
// // distinct: true,
|
|
// group: ['hotel_id'],
|
|
// });
|
|
// const count = countRows.length;
|
|
// const findIds = countRows.map((item) => item.hotel_id);
|
|
|
|
const { count, rows } = await Hotelinfo.findAndCountAll({
|
|
// const [ rows ] = await Hotelinfo.findAll({
|
|
include: [
|
|
{
|
|
model: Hotelinfo2,
|
|
as: 'lgc_info',
|
|
attributes: [
|
|
['hi2_sn', 'sn'],
|
|
'hotel_id',
|
|
'lgc',
|
|
'locale',
|
|
['hi2_hotel_name', 'hotel_name'],
|
|
['hi2_address', 'address'],
|
|
['hi2_description', 'description'],
|
|
['h2_review_desc', 'review_desc'],
|
|
['h2_location_highlight_desc', 'location_highlight_desc'],
|
|
],
|
|
required: false,
|
|
separate: true,
|
|
},
|
|
{ model: City, as: 'city', attributes: ['id', 'name'], where: { lgc: 2 }, required: false, separate: true, },
|
|
{ model: Country, as: 'country', attributes: ['id', 'name'], where: { lgc: 2 }, required: false, separate: true, },
|
|
],
|
|
// include: [{ model: Hotelinfo2, as: 'h2', required: true }],
|
|
where: {
|
|
[Op.or]: keywordSearch,
|
|
// hotel_id: findIds,
|
|
},
|
|
order: keywordOrder,
|
|
...options,
|
|
// raw: true,
|
|
nest: true,
|
|
});
|
|
|
|
return { count, rows: rows.map((item) => item.dataValues) };
|
|
// return { count, rows };
|
|
};
|
|
|
|
getLastPageIndex = async () => {
|
|
const ret = await HeytripIds.max('page_index');
|
|
return ret;
|
|
};
|
|
|
|
syncAids = async () => {
|
|
const lastPageIndex = await this.getLastPageIndex();
|
|
const pageIndex = lastPageIndex + 1;
|
|
|
|
const ids = await AvailableAccommodationIds(pageIndex);
|
|
if (isEmpty(ids)) {
|
|
return {
|
|
nextPage: false,
|
|
pageIndex,
|
|
};
|
|
}
|
|
|
|
const insertRows = ids.map((id) => ({ hotel_id: id, page_index: pageIndex }));
|
|
await HeytripIds.bulkCreate(insertRows);
|
|
|
|
return {
|
|
nextPage: true,
|
|
pageIndex,
|
|
};
|
|
};
|
|
|
|
newHotels = async () => {
|
|
const [rows] = await Sequelize.query(
|
|
'SELECT i.hotel_id, IFNULL(h.hi_sn ,0) info_exists FROM heytrip_ids as i LEFT JOIN hotelinfo AS h ON h.hotel_id = i.hotel_id WHERE h.hi_sn IS NULL AND update_flag != 0 ORDER BY info_exists LIMIT 10'
|
|
);
|
|
return rows;
|
|
};
|
|
|
|
newHotelsLgc = async (lgc) => {
|
|
// const [rows] = await Sequelize.query(
|
|
// `SELECT h.hotel_id
|
|
// FROM hotelinfo AS h
|
|
// LEFT JOIN hotelinfo2 AS h2 ON h.hotel_id =h2.hotel_id
|
|
// AND h2.lgc = ${lgc}
|
|
// WHERE h2.hi2_sn IS NULL LIMIT 10`
|
|
// );
|
|
const [rows] = await Sequelize.query(
|
|
`SELECT i.hotel_id ,IFNULL(h.hi2_sn, 0) info_exists
|
|
FROM heytrip_ids AS i
|
|
LEFT JOIN hotelinfo2 AS h ON h.hotel_id = i.hotel_id
|
|
AND h.lgc = ${lgc}
|
|
WHERE h.hi2_sn IS NULL
|
|
AND update_flag != 99
|
|
ORDER BY info_exists LIMIT 10`
|
|
);
|
|
const res = await this.syncInitHotelLgcDetailsAction(rows, LGC_MAPPED[lgc]);
|
|
return res;
|
|
};
|
|
|
|
chinaHotels = async () => {
|
|
const [rows] = await Sequelize.query(
|
|
'SELECT i.hotel_id, IFNULL(h.hi_sn ,0) info_exists FROM heytrip_ids as i LEFT JOIN hotelinfo AS h ON h.hotel_id = i.hotel_id WHERE h.hi_sn IS NULL AND update_flag != 0 AND i.hotel_id > 20000000 ORDER BY info_exists LIMIT 10'
|
|
);
|
|
const res = await this.syncInitHotelDetailsAction(rows, LGC_MAPPED['2']);
|
|
return res;
|
|
};
|
|
chinaHotelsLgc2 = async (lgc) => {
|
|
// const [rows] = await Sequelize.query(
|
|
// `SELECT h.hotel_id
|
|
// FROM hotelinfo AS h
|
|
// LEFT JOIN hotelinfo2 AS h2 ON h.hotel_id =h2.hotel_id
|
|
// AND h2.lgc = ${lgc}
|
|
// WHERE h2.hi2_sn IS NULL LIMIT 10`
|
|
// );
|
|
const [rows] = await Sequelize.query(
|
|
`SELECT i.hotel_id ,IFNULL(h.hi2_sn, 0) info_exists
|
|
FROM heytrip_ids AS i
|
|
INNER JOIN hotelinfo AS h1 ON h1.hotel_id =i.hotel_id
|
|
LEFT JOIN hotelinfo2 AS h ON h.hotel_id = i.hotel_id
|
|
AND h.lgc = ${lgc}
|
|
WHERE h.hi2_sn IS NULL
|
|
AND update_flag != 99
|
|
AND h1.country_code ='CN'
|
|
-- AND i.hotel_id > 20000000
|
|
ORDER BY info_exists LIMIT 10`
|
|
);
|
|
const res = await this.syncInitHotelLgcDetailsAction(rows, LGC_MAPPED[lgc]);
|
|
return res;
|
|
};
|
|
|
|
syncInitHotelDetailsAction = async (rows, lgcObj = LGC_MAPPED[DEFAULT_LGC]) => {
|
|
let allIds = [];
|
|
try {
|
|
|
|
allIds = rows.map((item) => item.hotel_id);
|
|
const updateIds = rows.filter((item) => item.info_exists !== 0).map((item) => item.hotel_id);
|
|
const newIds = rows.filter((item) => item.info_exists === 0).map((item) => item.hotel_id);
|
|
|
|
if (isEmpty(rows)) {
|
|
return { next: !isEmpty(allIds), data: allIds };
|
|
}
|
|
const res = await AccommodationsDetails({
|
|
Language: lgcObj.locale,
|
|
AccommodationIds: allIds,
|
|
});
|
|
|
|
const resIds = res.map((item) => item.HotelId);
|
|
// hotel info
|
|
const insertData = extractDetails(res, lgcObj);
|
|
// return insertData; // debug: 0
|
|
|
|
/** 开始Database */
|
|
const sequelizeOptions = { logging: false };
|
|
const result = await Sequelize.transaction(async t => {
|
|
let Info;
|
|
if ( ! isEmpty(insertData.info)) Info = await Hotelinfo.bulkCreate(insertData.info, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.info2)) await Hotelinfo2.bulkCreate(insertData.info2, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.rooms)) await Rooms.bulkCreate(insertData.rooms, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.images)) await Images.bulkCreate(insertData.images, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.facility)) await Facility.bulkCreate(insertData.facility, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.infos)) await Informations.bulkCreate(insertData.infos, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.reviews)) await Reviews.bulkCreate(insertData.reviews, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.reviews_summaries)) await ReviewsSummaries.bulkCreate(insertData.reviews_summaries, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.locations)) await Locations.bulkCreate(insertData.locations, sequelizeOptions);
|
|
if ( ! isEmpty(allIds)) await HeytripIds.update({ update_flag: 0 }, { where: { hotel_id: allIds } });
|
|
return Info;
|
|
});
|
|
|
|
return { next: !isEmpty(allIds), data: allIds };
|
|
|
|
} catch (error) {
|
|
console.log(error);
|
|
|
|
return { next: false, data: allIds };
|
|
}
|
|
}
|
|
|
|
syncInitHotelLgcDetailsAction = async (rows, lgcObj = LGC_MAPPED[DEFAULT_LGC]) => {
|
|
let allIds = [];
|
|
try {
|
|
|
|
allIds = rows.map((item) => item.hotel_id);
|
|
if (isEmpty(rows)) {
|
|
return { next: !isEmpty(allIds), data: allIds };
|
|
}
|
|
const _BaseInfoExists = await Hotelinfo.findAll({ where: { hotel_id: allIds } });
|
|
const updateIds = _BaseInfoExists.map((item) => `${item.hotel_id}`);
|
|
console.log('updateIds', updateIds);
|
|
|
|
|
|
const res = await AccommodationsDetails({
|
|
Language: lgcObj.locale,
|
|
AccommodationIds: allIds,
|
|
});
|
|
|
|
const resIds = res.map((item) => item.HotelId);
|
|
// hotel info
|
|
const insertData = resolveDetails(res, lgcObj);
|
|
// return insertData; // debug: 0
|
|
|
|
/** 开始Database */
|
|
const result = await Sequelize.transaction(async transaction => {
|
|
const sequelizeOptions = { logging: false, transaction };
|
|
let Info;
|
|
|
|
const newInfo = insertData.info.filter(iitem => !updateIds.includes(`${iitem.hotel_id}`));
|
|
console.log('newInfo', newInfo.map(xx => xx.hotel_id));
|
|
if ( ! isEmpty(newInfo)) Info = await Hotelinfo.bulkCreate(newInfo, sequelizeOptions);
|
|
|
|
if ( ! isEmpty(insertData.info2)) await Hotelinfo2.bulkCreate(insertData.info2, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.rooms)) await Rooms.bulkCreate(insertData.rooms, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.images)) await Images.bulkCreate(insertData.images, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.facility)) await Facility.bulkCreate(insertData.facility, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.infos)) await Informations.bulkCreate(insertData.infos, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.reviews)) await Reviews.bulkCreate(insertData.reviews, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.reviews_summaries)) await ReviewsSummaries.bulkCreate(insertData.reviews_summaries, sequelizeOptions);
|
|
if ( ! isEmpty(insertData.locations)) await Locations.bulkCreate(insertData.locations, sequelizeOptions);
|
|
|
|
if ( ! isEmpty(newInfo)) await HeytripIds.update({ update_flag: 0 }, { where: { hotel_id: newInfo.map(x => x.hotel_id) } });
|
|
|
|
return Info;
|
|
});
|
|
|
|
return { next: !isEmpty(allIds), data: allIds };
|
|
|
|
} catch (error) {
|
|
console.log(error);
|
|
|
|
return { next: false, data: allIds };
|
|
}
|
|
};
|
|
|
|
getHotelAvailability = async (param) => {
|
|
const { hotel_id, checkin, checkout, adults, children_ages, rooms, nationality } = param;
|
|
const paramBody = {
|
|
Language: 'en-US',
|
|
// Language: 'zh-CN',
|
|
AccommodationIds: [Number(hotel_id)],
|
|
CheckInDate: checkin,
|
|
CheckOutDate: checkout,
|
|
Nationality: nationality || 'CN', // 默认取中国报价
|
|
NumberOfAdults: adults || 1,
|
|
ChildrenAges: children_ages || null, // 入住每个儿童年龄 [6,8]
|
|
// ChildrenAges: null,
|
|
NumberOfRooms: rooms || 1,
|
|
Currency: 'CNY',
|
|
};
|
|
const _quoteRes = await Availability(paramBody);
|
|
const quoteRes = resolveRatePlans(_quoteRes);
|
|
return quoteRes;
|
|
};
|
|
}
|
|
module.exports = new Heytrip();
|