This commit is contained in:
@@ -147,7 +147,11 @@ function updateBookingRoom(req, res) {
|
||||
const totalGuests = (booking.adults || 0) + (booking.children || 0);
|
||||
calculateNightPrices(room.type, booking.checkin_date, booking.checkout_date, (err, baseSum) => {
|
||||
if (err) return res.status(400).json({ error: err.message });
|
||||
const basePrice = baseSum * Math.max(1, totalGuests);
|
||||
let basePrice = baseSum;
|
||||
if (totalGuests > (room.max_guests || 99) && room.extra_beds > 0) {
|
||||
const nights = config.calculateNights(booking.checkin_date, booking.checkout_date);
|
||||
basePrice += (totalGuests - (room.max_guests || 99)) * room.extra_bed_price * nights;
|
||||
}
|
||||
const discountAmount = Math.round(basePrice * (booking.discount_percent || 0) / 100);
|
||||
const totalPrice = basePrice - discountAmount;
|
||||
|
||||
@@ -307,17 +311,29 @@ function updateBookingDetails(req, res) {
|
||||
if (!roomType) {
|
||||
return finishUpdate();
|
||||
}
|
||||
calculateNightPrices(roomType, finalCheckin, finalCheckout, (err, baseSum) => {
|
||||
if (err) return res.status(500).json({ error: err.message });
|
||||
const basePrice = baseSum * totalGuests;
|
||||
const discountPercent = row.discount_percent || 0;
|
||||
const discountAmount = Math.round(basePrice * discountPercent / 100);
|
||||
const totalPrice = basePrice - discountAmount;
|
||||
db.run(`UPDATE bookings SET base_price = ?, discount_amount = ?, total_price = ? WHERE id = ?`,
|
||||
[basePrice, discountAmount, totalPrice, bookingId], (err) => {
|
||||
if (err) return res.status(500).json({ error: 'Database error' });
|
||||
finishUpdate();
|
||||
});
|
||||
db.get(`SELECT max_guests, extra_beds, extra_bed_price FROM rooms WHERE type = ? AND is_active = 1 LIMIT 1`,
|
||||
[roomType], (err, rm) => {
|
||||
if (err) return res.status(500).json({ error: 'Database error' });
|
||||
const roomMax = rm ? rm.max_guests : 99;
|
||||
const roomExtraBeds = rm ? rm.extra_beds : 0;
|
||||
const roomExtraBedPrice = rm ? rm.extra_bed_price : 0;
|
||||
|
||||
calculateNightPrices(roomType, finalCheckin, finalCheckout, (err, baseSum) => {
|
||||
if (err) return res.status(500).json({ error: err.message });
|
||||
const nights = config.calculateNights(finalCheckin, finalCheckout);
|
||||
let basePrice = baseSum;
|
||||
if (totalGuests > roomMax && roomExtraBeds > 0) {
|
||||
basePrice += (totalGuests - roomMax) * roomExtraBedPrice * nights;
|
||||
}
|
||||
const discountPercent = row.discount_percent || 0;
|
||||
const discountAmount = Math.round(basePrice * discountPercent / 100);
|
||||
const totalPrice = basePrice - discountAmount;
|
||||
db.run(`UPDATE bookings SET base_price = ?, discount_amount = ?, total_price = ? WHERE id = ?`,
|
||||
[basePrice, discountAmount, totalPrice, bookingId], (err) => {
|
||||
if (err) return res.status(500).json({ error: 'Database error' });
|
||||
finishUpdate();
|
||||
});
|
||||
});
|
||||
});
|
||||
function finishUpdate() {
|
||||
db.get(`SELECT b.*, p.code as promocode_code, r.name as room_name
|
||||
@@ -353,18 +369,29 @@ function validatePromocodeAPI(req, res) {
|
||||
if (err) return res.status(500).json({ error: 'Database error' });
|
||||
if (!promo) return res.status(404).json({ error: 'Invalid or expired promocode' });
|
||||
const guestsCount = parseInt(guests) || 1;
|
||||
calculateNightPrices(room_type, checkin, checkout, (err, baseSum) => {
|
||||
if (err) return res.status(400).json({ error: err.message });
|
||||
const basePrice = baseSum * guestsCount;
|
||||
const discountAmount = Math.round(basePrice * promo.discount_percent / 100);
|
||||
const totalPrice = basePrice - discountAmount;
|
||||
res.json({
|
||||
valid: true,
|
||||
discount_percent: promo.discount_percent,
|
||||
base_price: basePrice,
|
||||
discount_amount: discountAmount,
|
||||
total_price: totalPrice,
|
||||
code: promo.code
|
||||
db.get(`SELECT max_guests, extra_beds, extra_bed_price FROM rooms WHERE type = ? AND is_active = 1 LIMIT 1`,
|
||||
[room_type], (err, rm) => {
|
||||
if (err) return res.status(500).json({ error: 'Database error' });
|
||||
const roomMax = rm ? rm.max_guests : 99;
|
||||
const roomExtraBeds = rm ? rm.extra_beds : 0;
|
||||
const roomExtraBedPrice = rm ? rm.extra_bed_price : 0;
|
||||
calculateNightPrices(room_type, checkin, checkout, (err, baseSum) => {
|
||||
if (err) return res.status(400).json({ error: err.message });
|
||||
let basePrice = baseSum;
|
||||
if (guestsCount > roomMax && roomExtraBeds > 0) {
|
||||
const nights = config.calculateNights(checkin, checkout);
|
||||
basePrice += (guestsCount - roomMax) * roomExtraBedPrice * nights;
|
||||
}
|
||||
const discountAmount = Math.round(basePrice * promo.discount_percent / 100);
|
||||
const totalPrice = basePrice - discountAmount;
|
||||
res.json({
|
||||
valid: true,
|
||||
discount_percent: promo.discount_percent,
|
||||
base_price: basePrice,
|
||||
discount_amount: discountAmount,
|
||||
total_price: totalPrice,
|
||||
code: promo.code
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -112,9 +112,28 @@ function createBooking(req, res) {
|
||||
});
|
||||
}
|
||||
|
||||
calculateNightPrices(roomType, checkin, checkout, (err, baseSum) => {
|
||||
if (err) return res.status(400).json({ error: err.message });
|
||||
const basePrice = baseSum * (parseInt(adults) || 1);
|
||||
db.get(`SELECT max_guests, extra_beds, extra_bed_price FROM rooms WHERE type = ? AND is_active = 1 LIMIT 1`,
|
||||
[roomType], (err, roomRow) => {
|
||||
if (err) return res.status(500).json({ error: 'Database error' });
|
||||
const roomMax = roomRow ? roomRow.max_guests : 99;
|
||||
const roomExtraBeds = roomRow ? roomRow.extra_beds : 0;
|
||||
const roomExtraBedPrice = roomRow ? roomRow.extra_bed_price : 0;
|
||||
const adultsCount = parseInt(adults) || 1;
|
||||
|
||||
if (adultsCount > roomMax && roomExtraBeds === 0) {
|
||||
return res.status(400).json({ error: `Максимум ${roomMax} гостей для этого типа номера` });
|
||||
}
|
||||
if (adultsCount > roomMax + 1) {
|
||||
return res.status(400).json({ error: `Максимум ${roomMax + 1} гостей (включая доп. место)` });
|
||||
}
|
||||
|
||||
calculateNightPrices(roomType, checkin, checkout, (err, baseSum) => {
|
||||
if (err) return res.status(400).json({ error: err.message });
|
||||
let basePrice = baseSum;
|
||||
if (adultsCount > roomMax && roomExtraBeds > 0) {
|
||||
const nights = config.calculateNights(checkin, checkout);
|
||||
basePrice += (adultsCount - roomMax) * roomExtraBedPrice * nights;
|
||||
}
|
||||
|
||||
validatePromocode(promocode, (err, promo) => {
|
||||
if (err) return res.status(500).json({ error: 'Database error' });
|
||||
@@ -156,6 +175,7 @@ function createBooking(req, res) {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getBookings(req, res) {
|
||||
|
||||
@@ -1395,6 +1395,13 @@ h1, h2, h3, h4 {
|
||||
box-shadow: 0 10px 30px rgba(10,77,104,0.3);
|
||||
}
|
||||
|
||||
/* Extra bed option in guest select */
|
||||
select option[data-extra="1"] {
|
||||
background: #fef3e2;
|
||||
color: #92400e;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Floating phone button */
|
||||
.float-phone {
|
||||
position: fixed;
|
||||
|
||||
@@ -116,7 +116,7 @@ document.querySelectorAll('.btn-book').forEach(btn => {
|
||||
});
|
||||
});
|
||||
|
||||
function updateGuestOptionsDynamic(roomType, maxGuests) {
|
||||
function updateGuestOptionsDynamic(roomType, maxGuests, extraBeds = 0, extraBedPrice = 0) {
|
||||
const guestsSelect = document.querySelector('[name="guests"]');
|
||||
if (!guestsSelect) return;
|
||||
|
||||
@@ -126,16 +126,21 @@ function updateGuestOptionsDynamic(roomType, maxGuests) {
|
||||
let text = rt(key, i === 1 ? '1 гость' : (i < 5 ? i + ' гостя' : i + ' гостей'));
|
||||
options.push(`<option value="${i}">${text}</option>`);
|
||||
}
|
||||
if (extraBeds > 0 && extraBedPrice > 0) {
|
||||
options.push(`<option value="${maxGuests + 1}" data-extra="1">${maxGuests + 1} гостя + доп. место (+${extraBedPrice} ₽/ночь)</option>`);
|
||||
}
|
||||
|
||||
guestsSelect.innerHTML = options.join('');
|
||||
}
|
||||
|
||||
window.updateRoomPricesData = function(prices, maxGuests) {
|
||||
window.updateRoomPricesData = function(prices, maxGuests, extraBeds, extraBedPrices) {
|
||||
Object.assign(ROOM_PRICES, prices);
|
||||
Object.assign(ROOM_MAX_GUESTS, maxGuests);
|
||||
if (extraBeds) Object.assign(ROOM_EXTRA_BEDS, extraBeds);
|
||||
if (extraBedPrices) Object.assign(ROOM_EXTRA_BED_PRICES, extraBedPrices);
|
||||
};
|
||||
|
||||
function updateGuestOptions(room) {
|
||||
function updateGuestOptions(room, extraBeds = 0, extraBedPrice = 0) {
|
||||
const guestsSelect = document.querySelector('[name="guests"]');
|
||||
if (!guestsSelect) return;
|
||||
|
||||
@@ -146,6 +151,9 @@ function updateGuestOptions(room) {
|
||||
let text = rt(key, i === 1 ? '1 гость' : (i < 5 ? i + ' гостя' : i + ' гостей'));
|
||||
options.push(`<option value="${i}">${text}</option>`);
|
||||
}
|
||||
if (extraBeds > 0 && extraBedPrice > 0) {
|
||||
options.push(`<option value="${maxGuests + 1}" data-extra="1">${maxGuests + 1} гостя + доп. место (+${extraBedPrice} ₽/ночь)</option>`);
|
||||
}
|
||||
|
||||
guestsSelect.innerHTML = options.join('');
|
||||
}
|
||||
@@ -184,6 +192,8 @@ function hideGuestOptionsUpdate() {}
|
||||
// Price calculation
|
||||
const ROOM_PRICES = { '2x-местный': 1500, '3х-местный': 2000, 'Семейный': 3000, 'Люкс': 4500 };
|
||||
const ROOM_MAX_GUESTS = { '2x-местный': 2, '3х-местный': 3, 'Семейный': 4, 'Люкс': 4 };
|
||||
const ROOM_EXTRA_BEDS = {};
|
||||
const ROOM_EXTRA_BED_PRICES = {};
|
||||
let currentPromocodeData = null;
|
||||
|
||||
function calculateNights(checkin, checkout) {
|
||||
@@ -254,7 +264,14 @@ async function checkPromocode() {
|
||||
}
|
||||
|
||||
const guests = parseInt(document.querySelector('[name="guests"]').value) || 1;
|
||||
const basePrice = ROOM_PRICES[room] ? ROOM_PRICES[room] * guests * calculateNights(checkin, checkout) : 0;
|
||||
const nightCount = calculateNights(checkin, checkout);
|
||||
const maxGuests = ROOM_MAX_GUESTS[room] || 4;
|
||||
const extraBeds = ROOM_EXTRA_BEDS[room] || 0;
|
||||
const extraBedPrice = ROOM_EXTRA_BED_PRICES[room] || 0;
|
||||
let basePrice = ROOM_PRICES[room] ? ROOM_PRICES[room] * nightCount : 0;
|
||||
if (guests > maxGuests && extraBeds > 0) {
|
||||
basePrice += (guests - maxGuests) * extraBedPrice * nightCount;
|
||||
}
|
||||
|
||||
if (!promocode) {
|
||||
updatePriceDisplay(basePrice, 0, 0, basePrice);
|
||||
|
||||
@@ -113,7 +113,7 @@ function renderRoomsPublic(rooms) {
|
||||
<span class="amount">${rt('rooms.from', 'от')} ${room.price_per_night || 0} ₽</span>
|
||||
<span class="period"> ${rt('rooms.per_night', '/ ночь')}</span>
|
||||
</div>
|
||||
<button class="btn-book" data-bs-toggle="modal" data-bs-target="#bookingModal" data-room-id="${room.id}" data-room-type="${room.type}" data-room-name="${escapeHtml(room.name)}" data-max-guests="${room.max_guests}">${rt('rooms.book', 'Забронировать')}</button>
|
||||
<button class="btn-book" data-bs-toggle="modal" data-bs-target="#bookingModal" data-room-id="${room.id}" data-room-type="${room.type}" data-room-name="${escapeHtml(room.name)}" data-max-guests="${room.max_guests}" data-extra-beds="${room.extra_beds || 0}" data-extra-bed-price="${room.extra_bed_price || 0}">${rt('rooms.book', 'Забронировать')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,12 +180,16 @@ function applyCarouselFrame(index, images) {
|
||||
function updateRoomPrices(rooms) {
|
||||
const prices = {};
|
||||
const maxGuests = {};
|
||||
const extraBeds = {};
|
||||
const extraBedPrices = {};
|
||||
rooms.forEach(room => {
|
||||
prices[room.type] = room.price_per_night;
|
||||
maxGuests[room.type] = room.max_guests;
|
||||
extraBeds[room.type] = room.extra_beds || 0;
|
||||
extraBedPrices[room.type] = room.extra_bed_price || 0;
|
||||
});
|
||||
if (window.updateRoomPricesData) {
|
||||
window.updateRoomPricesData(prices, maxGuests);
|
||||
window.updateRoomPricesData(prices, maxGuests, extraBeds, extraBedPrices);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,9 +200,11 @@ function initRoomBookingHandlers() {
|
||||
const roomType = this.getAttribute('data-room-type');
|
||||
const roomName = this.getAttribute('data-room-name');
|
||||
const maxGuests = parseInt(this.getAttribute('data-max-guests')) || 4;
|
||||
const extraBeds = parseInt(this.getAttribute('data-extra-beds')) || 0;
|
||||
const extraBedPrice = parseInt(this.getAttribute('data-extra-bed-price')) || 0;
|
||||
document.getElementById('selectedRoom').value = roomType;
|
||||
document.getElementById('selectedRoomId').value = roomId;
|
||||
updateGuestOptionsDynamic(roomType, maxGuests);
|
||||
updateGuestOptionsDynamic(roomType, maxGuests, extraBeds, extraBedPrice);
|
||||
hidePriceInfo();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user