apc-domain
Version:
APC Domain Information Package
195 lines (159 loc) • 5.57 kB
JavaScript
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