фикс3
All checks were successful
Deploy hotel / deploy-kdo (push) Successful in 58s

This commit is contained in:
2026-07-26 23:57:14 +05:00
parent 4989816b2b
commit 0277b46e33
5 changed files with 111 additions and 34 deletions

View File

@@ -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
});
});
});
});

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();
});
});