diff --git a/basket/Basket.js b/basket/Basket.js index 77f352d..f8d8c20 100644 --- a/basket/Basket.js +++ b/basket/Basket.js @@ -152,6 +152,16 @@ export default class Basket { // load default start date instance if (!startDateInstance) startDateInstance = this.getCurrentDateInstance() + // check that selected date and timespan is within available dates + const tmpBasketEntry = new BasketEntry({}) + tmpBasketEntry.setValidFrom(startDateInstance) + tmpBasketEntry.setProductDefinitionInstance(definition) + const checkResult = this.checkAvailableDates([tmpBasketEntry]) + if (!checkResult) { + EventBus.$emit('spinnerHide') + return false + } + // set standard user data if (!userData) { userData = new UserData({ @@ -215,6 +225,13 @@ export default class Basket { * @returns {Promise} */ async updateBasketEntries(basketEntriesArray) { + // check validity dates + const checkResult = this.checkAvailableDates(basketEntriesArray) + if (!checkResult) { + EventBus.$emit('spinnerHide') + return false + } + // prepare basket entries for the api const preparedBasketEntries = basketEntriesArray.map((basketEntry) => { basketEntry.getUserData().setCompleteForCheckout(basketEntry) @@ -285,6 +302,13 @@ export default class Basket { ) { if (showSpinner) EventBus.$emit('spinnerShow') + // check that selected date and timespan is within available dates + const checkResult = this.checkAvailableDates([basketEntryInstance]) + if (!checkResult) { + EventBus.$emit('spinnerHide') + return false + } + // is the basket entry ready to be complete for checkout ? basketEntryInstance .getUserData() @@ -813,6 +837,40 @@ export default class Basket { return true } + /** + * Is the booked time span within the available dates of a product (considering availability range and validity dates) + * @param basketEntries: BasketEntry[] + * @return {boolean} + */ + checkAvailableDates(basketEntries) { + if (!basketEntries || !basketEntries.length) { + throw new Error('No product definitions provided in duration check') + } + const shopModulesInstance = store.getters.getShopModulesInstance() + // iterate product definitions + for (let i = 0; i < basketEntries.length; i++) { + const basketEntry = basketEntries[i] + if (basketEntry.isRequiredEntry() || basketEntry.isEventEntry()) { + // no product would be found + continue + } + const bookingStart = basketEntry.getValidFrom() + const productDefinition = basketEntry.getProductDefinition() + const productId = productDefinition.getProductId() + const productInstance = shopModulesInstance.getProductInstanceByProductId( + productId + ) + const checkResult = productInstance.checkAvailableDates( + productDefinition, + bookingStart + ) + if (!checkResult) { + return false + } + } + return true + } + /** * LATEST BOOKING TIME CONSTRAINT */ diff --git a/products/Product.js b/products/Product.js index 699a99e..db92b43 100644 --- a/products/Product.js +++ b/products/Product.js @@ -655,7 +655,8 @@ export default class Product { filterProductDefinitionsByProductDefinitionAndAttributeKey( attributeKey, productDefinition, - excludeAttributeKeys = [] + excludeAttributeKeys = [], + includeMauiOnly = false ) { let filteredProductDefinitions = [] @@ -692,6 +693,12 @@ export default class Product { filteredProductDefinitions.push(currentProductDefinition) } + if (!includeMauiOnly) { + filteredProductDefinitions = filteredProductDefinitions.filter( + (prodDef) => !prodDef.isMauiOnly() + ) + } + // sort filtered product definitions return filteredProductDefinitions.sort( (productDefinitionA, productDefinitionB) => { @@ -900,6 +907,43 @@ export default class Product { return this.getAvailabilityDateRanges().getDateList(type) } + /** + * Checks, if a product definition of this product has the full time span within validity dates and availability ranges + * @param productDefinitionInstance + * @param bookingStartInstance + * @return {boolean} + */ + checkAvailableDates(productDefinitionInstance, bookingStartInstance) { + // get an list of available dates of the product + const availableDateList = this.getAvailableDates('date') + // get a list of dates of the product definition (booking date + duration days) + const durationDays = productDefinitionInstance.getDurationDays() + const endDate = new Date( + bookingStartInstance.getFullYear(), + bookingStartInstance.getMonth(), + bookingStartInstance.getDate() + durationDays - 1, + 0, + 0, + 0, + 0 + ) + const bookingDateList = DateHelper.getDateList( + bookingStartInstance, + endDate + ) + for (let i = 0; i < bookingDateList.length; i++) { + const bookingDate = bookingDateList[i] + const foundAvailableDate = availableDateList.find((availableDate) => { + return availableDate.getTime() === bookingDate.getTime() + }) + if (!foundAvailableDate) { + EventBus.$emit('notify', i18n.t('basket.dateNotAvailable')) + return false + } + } + return true + } + getCurrentSeasonStart() { const availableDates = this.getAvailableDates() const todayMs = new Date().setHours(0, 0, 0, 0)