UNPKG

apc-domain

Version:
195 lines (159 loc) 5.57 kB
'use strict' const Moment = require('moment') const BankHolidayFeed = require('uk-bank-holidays') const ServiceList = require('../servicesList') class Services { /** * Return delivery period for service code (days allowed, latest time) * * @param {string} serviceCode * @returns {object} */ static SetAdditionalPropertiesForServiceCode (ServiceCode) { let DeliveryPeriod = {} //TODO: Refactor this to a more dynamic array if (ServiceCode.includes('9') || ServiceCode.includes('10') || ServiceCode.includes('12') || ServiceCode.includes('16')) { // Then these services have a one day window DeliveryPeriod.MinDays = 1 DeliveryPeriod.MaxDays = 1 DeliveryPeriod.Window = { hour: 0, minute: 30, second: 0 } if (ServiceCode.includes('9')) { DeliveryPeriod.LatestTime = '09:00:00' } if (ServiceCode.includes('10')) { DeliveryPeriod.LatestTime = '10:00:00' } if (ServiceCode.includes('12')) { DeliveryPeriod.LatestTime = '12:00:00' } // Remember a 16 service can be delivered up until midnight that day (even though its 16..) if (ServiceCode.includes('16')) { DeliveryPeriod.LatestTime = '23:59:59' DeliveryPeriod.Window = { hour: 0, minute: 0, second: 0 } } } else { // Then it has to be a 2-5 day window (set 5 as window value) DeliveryPeriod.MinDays = 2 DeliveryPeriod.MaxDays = 5 DeliveryPeriod.LatestTime = '23:59:59' DeliveryPeriod.Window = { hour: 0, minute: 0, second: 0 } } return DeliveryPeriod } /** * Return details for service code from JSON file * * @param {string} ServiceCode * @returns {Object} * @throws {Error} */ static GetServiceDetails (ServiceCode) { let Services = ServiceList.filter(Service => { return Service.ServiceCode === ServiceCode }) if (Services.length > 0) { return Services[0] } else { throw Error('Service code not recognised') } } /** * Return the latest delivery time for the service code and consignment send date * * @param {Object} ServiceDetails * @param {Moment} SendDate * @param {Boolean} WithWindow * @returns {Moment} */ static async CalculateDeliveryDateTimeForServiceAndSendDate (ServiceDetails, SendDate, WithWindow) { // Add the maximum days for delivery window to the send date let DeliveryDate = Moment(SendDate.add(ServiceDetails.MaxDays, 'day')) let AdditionalDaysToAdd = 0 let DayOfPeriod = Moment(SendDate) // Initialise bank holiday service let bankHolidayFeed = new BankHolidayFeed() await bankHolidayFeed.load() let bankHolidays = bankHolidayFeed.divisions('england-and-wales') // If it's a Saturday service, override here. if (ServiceDetails.Saturday) { return this.FindNextSaturdayFromDate(SendDate) } // Otherwise, do the normal loop, skipping over bank holidays and Sat/Suns, etc do { let dayOfWeek = DayOfPeriod.format('d') // Is it Sunday if (dayOfWeek === '0') { if (!ServiceDetails.Sunday) { // AdditionalDaysToAdd++ DeliveryDate = Moment(DeliveryDate.add(1, 'day')) } } // Is it Saturday if (dayOfWeek === '6') { if (!ServiceDetails.Saturday) { // AdditionalDaysToAdd++ DeliveryDate = Moment(DeliveryDate.add(1, 'day')) } } // Is it a bank holiday if (bankHolidays.holidays(DayOfPeriod, DayOfPeriod).length > 0) { // AdditionalDaysToAdd++ DeliveryDate = Moment(DeliveryDate.add(1, 'day')) } DayOfPeriod = Moment(DayOfPeriod.add(1, 'day')) } while (DayOfPeriod <= DeliveryDate) DeliveryDate = DeliveryDate.add(AdditionalDaysToAdd, 'day') // Convert the time string to a moment object let DeliveryTime = Moment(ServiceDetails.LatestTime, 'HH:mm:ss') // Apply the time to the delivery date using moment DeliveryDate.set({ hour: DeliveryTime.get('hour'), minute: DeliveryTime.get('minute'), second: DeliveryTime.get('second') }) // If window flag is true, append window if (WithWindow) { DeliveryDate.add(ServiceDetails.Window) } return DeliveryDate } /** * Return the latest delivery time for the service code and consignment send date * * @param {string} ServiceCode * @param {Moment} SendDate * @param {Boolean} WithWindow * @returns {Moment} */ static CalculateDeliveryDateTime (ServiceCode, SendDate, WithWindow = false) { // Find the delivery period object for the service code let ServiceDetails = this.GetServiceDetails(ServiceCode) // Return the delivery date/time for the period and date passed in return this.CalculateDeliveryDateTimeForServiceAndSendDate(ServiceDetails, SendDate, WithWindow) } /** * Find the date of the next saturday for the date passed in * @param {Moment} Date * @returns {Moment} */ static FindNextSaturdayFromDate (Date) { let CurrentDate = Moment(Date) while (CurrentDate.format('d') !== '6') { CurrentDate = Moment(CurrentDate.add(1, 'day')) } return CurrentDate } } module.exports = Services