How to limit sessions per day for Wix Bookings by using Velo's custom development
Who is our customer, and what do they do?
Channel Vivid is a video production studio in New Orleans where they create commercial content for brands + individuals while also renting space to other creatives alike.
They passionately believe that video is the most effective way to communicate a message to an audience. They understand that retention is priceless.
Combined with an experienced team and the right tools, helping brands, businesses, and individuals alike channel their stories in the most tasteful way possible is their priority.
What was our customer's goal?
Our customer's requirement was that their booking system be able to utilize pricing plans to allow members to book a specified number of sessions in the studio per month, but only for a certain amount of time per day.

How did we solve their problem?
Wix Bookings & Wix Pricing Plans allowed us to easily enable members to book a specified number of sessions per month, but limiting the duration of the sessions per day was trickier.
Fortunately, using the built-in Velo Booking Events backend system and Velo's Wix Pricing Plans Backend API, we were able to implement these limitations.
What is the Wix Bookings app?
Wix Bookings is an easy-to-use scheduling system that lets customers book services online, so you can focus on managing your business.
Whether you offer workshops, courses, or private sessions - Wix Bookings has you covered. Customers can book services directly on your site. Click to add Wix Bookings to your site.
What is Velo (Wix's Custom Development Platform)?
Velo is a full-stack development platform that empowers you to rapidly build, manage and deploy professional web applications through Wix. Click to learn more about Velo.
How did we use Velo?
First, as with all Velo Events, we had to create an 'events.js' file in the Backend section of the Code Files tab in the Wix Editor.
The next step was to hook into the Wix Bookings app Booking Confirmed event, as documented in https://www.wix.com/velo/reference/wix-bookings-backend/events/onbookingconfirmed, so that when a booking was confirmed, our system would check to see if it was booked with a Pricing Plan. If so, use the Wix Pricing Plan Backend API to get the plan details and then pull the daily limit for that Plan which was stored as a Pricing Plan perk.
Then, we used the Wix Bookings Backend to query for bookings that were made by the same member for the same day that had also been booked with their pricing plan. Once these bookings had been queried and filtered, their durations were added together to see if their daily limit had been met. If so, we then used Wix Bookings Backend API to cancel the booking and notify the customer that the booking they had attempted to book exceeded their daily limitation.
What was our customer's reaction to the solution?

"They are the type of professionals I like to work with. They figure out your needs while also setting you up for success for the long haul. Will be back for more work in the future!" Allen Esmail, Owner of Channel Vivid
Below is the code used. Check it out!
import { bookings } from "wix-bookings-backend";
import wixPricingPlansBackend from "wix-pricing-plans-backend";
const declineBookingOptions = {
participantNotification: {
notifyParticipants: true,
message:
"Sorry, but your booking request has been declined due to daily limits reached.",
},
suppressAuth: true,
};
export async function wixBookings_onBookingConfirmed(event) {
console.log("Booking confirmed");
console.log(event);
const bookingId = event.booking._id;
const contactId = event.booking.formInfo.contactDetails.contactId;
const start = event.booking.bookedEntity.singleSession.start;
let subtractDay = false;
const startDate = new Date(start);
const day = startDate.toISOString().split("T")[0];
const startTime = parseInt(startDate.toISOString().split("T")[1].slice(0, 2));
if (startTime >= 0 && startTime <= 6) {
subtractDay = true;
}
let startOfDay = day + "T06:00:00.000Z";
let endOfDay = day + "T06:00:00.000Z";
let startOfDayTime = new Date(startOfDay).getTime();
let endOfDayTime = new Date(endOfDay).getTime();
if (subtractDay) {
let startOfYesterday = new Date(startOfDay);
startOfYesterday.setDate(startOfYesterday.getDate() - 1);
startOfDayTime = startOfYesterday.getTime();
startOfDay = startOfYesterday.toISOString();
} else {
const newEndOfDayDate = new Date(endOfDay);
newEndOfDayDate.setDate(newEndOfDayDate.getDate() + 1);
endOfDayTime = newEndOfDayDate.getTime();
}
console.log(startOfDay);
const planId =
event.booking?.paymentDetails?.pricingPlanDetails?.plan?.planId;
console.log("Plan ID = " + planId);
if (planId) {
const plan = await wixPricingPlansBackend
.getPlan(planId)
.then((plan) => {
return plan;
})
.catch((err) => console.log("Error getting plan " + err));
if (plan) {
const dailyLimitPerk = plan.perks[1];
const dailyLimit = parseInt(dailyLimitPerk.split(" ")[0]);
console.log("Daily Limit found of " + dailyLimit + " hours per day");
console.log("Checking for other bookings on the day");
const queryOptions = {
suppressAuth: true,
};
const sameDayBookings = await bookings
.queryBookings()
.eq("contactId", contactId)
.ge("startTime", startOfDay)
.find(queryOptions)
.then((bs) => {
console.log("Bookings found for contact id: " + contactId);
console.log(bs.items);
const sameDayBookings = bs.items.filter((booking) => {
const startTime = new Date(
booking.bookedEntity.singleSession.start
).getTime();
console.log("Start time is " + startTime);
const isSameDayOfBooking =
startTime >= startOfDayTime && startTime <= endOfDayTime;
const bookingPlan =
booking.paymentDetails?.pricingPlanDetails?.plan?.planId;
if (
isSameDayOfBooking &&
booking._id !== bookingId &&
bookingPlan === planId
) {
return true;
}
return false;
});
return sameDayBookings;
})
.catch((err) => {
console.log(err);
return [];
});
console.log("Same Day Bookings");
console.log(sameDayBookings);
const durationOfOtherBookings = sameDayBookings.map((b) => {
return (
Math.abs(
b.bookedEntity.singleSession.end.getTime() -
b.bookedEntity.singleSession.start.getTime()
) / 36e5
);
});
const sumDurations = durationOfOtherBookings.reduce(
(sum, duration) => (sum += duration),
0
);
console.log("Summed durations");
console.log(sumDurations);
if (sumDurations >= dailyLimit) {
declineBookingOptions.participantNotification.message = `Sorry, this booking would exceed your ${dailyLimit} hour daily limit.`;
bookings.cancelBooking(bookingId, declineBookingOptions);
}
} else {
console.log("Plan could not be found with planId: " + planId);
}
} else {
console.log("No plan id found for contact " + contactId);
}
}
About our company
RHM specializes in helping businesses of all sizes and types achieve their digital and web marketing needs. Whether it's designing a new website, building an app, performing custom development, or running AdWords for clients, our goal is to showcase how you are the best at whatever you are doing and help people connect with you. Click here to visit our homepage.
Contact Robert Hebert to get started on your next project.
Email robert@roberthebertmedia.com or visit our contact page.






Đây là kiểu bài hướng dẫn viết code mà tôi thích, vì tác giả đưa cả đoạn mã lẫn lý do đặt giới hạn vào, chứ không chỉ khoe kết quả. Phần khó nhất với tôi vẫn là chỗ đếm lại số phiên trong một ngày, vì ranh giới giữa ngày theo múi giờ máy chủ và ngày theo múi giờ mình khó thống nhất. Tôi hay đọc loại bài này lúc khuya khi code xong phần chính, chỉ cần chạy thử thôi. Trước đó có đứa bạn cùng nghề nhắc tới tên TN88 trong chuyện xếp bài cho đỡ tay sau ca đêm, tôi nghe vậy thôi chứ chưa xem gì. Còn cách tách bạch giữa khách đặt lịch và…
Vừa đọc xong bài hướng dẫn cách giới hạn số phiên đặt lịch mỗi ngày trên Wix Bookings bằng cách viết mã tùy chỉnh. Tôi không rành lập trình, nhưng phần giải thích lý do cần thiết lập giới hạn thì tôi theo được. Tôi nhớ từng giúp một người thân quản lý lịch hẹn ở phòng khám nhỏ, mỗi ngày phải tự đếm tay rất mệt. Trước đó không lâu, tôi cũng đọc được một bài nhắc đến TK88 trong danh sách các nền tảng game bài đổi thưởng, nhưng tôi chưa tìm hiểu gì thêm. Bài này cho tôi thấy việc tự động hóa nhỏ cũng tiết kiệm được nhiều thời gian.
Phần hướng dẫn giới hạn số phiên mỗi ngày trong Wix Bookings viết bằng Velo hơi dài nhưng dễ theo. Tôi chưa thử vì không có nhu cầu đặt lịch, chỉ tò mò cách người ta canh thiệp vào hành vi mặc định của hệ thống. Nhà tôi có thằng cháu hay lập trình, tối đến lại mở điện thoại chơi game bài đổi thưởng, có lần nó khoe tên 33WIN, tôi chỉ nghe chứ không hỏi thêm. Đọc bài này cũng thấy việc viết code giống nhau, đều là đi chỉnh cho nó chạy theo ý mình.
Bài viết chỉ cách giới hạn số phiên đặt chỗ mỗi ngày qua code khiến tôi nhớ hôm trò chuyện với anh đồng nghiệp cũ. Anh kể lúc tối hay ngồi chơi game bài đổi thưởng, có nhắc tới 8KBET, nhưng tôi không rõ lắm. Đọc bài, tôi thấy việc giới hạn số phiên như một cách giữ nhịp, không để mọi thứ chạy quá tay. Điều đó nghe đơn giản nhưng cần người biết sắp xếp, chứ không phải cứ để mặc cho hệ thống tự chạy.
The topic of making space for questions in the classroom gives me a few things to think about, especially when the discussion moves beyond general advice. A thoughtful pause can give quieter students time to develop an answer. It also gives the phrase student classroom participation a clearer meaning than a label on its own. I would be interested in a simple example, because it is often the ordinary details that make an idea memorable. What helps a classroom welcome questions that do not have an immediate solution?