Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create quarterly return logs #1603

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
104 changes: 72 additions & 32 deletions app/lib/return-periods.lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,46 @@

const { returnPeriodDates } = require('./static-lookups.lib.js')

/**
* Determine return periods for a given return cycle.
*
* This function calculates the upcoming return periods for the provided return cycle.
*
* The result includes the start date, end date, and due date for each period as well as the return cycle id.
*
* @param {object} returnCycle - The return cycle to be broken into periods.
*
* @returns {Array<object>} An object containing calculated dates for all return periods
*/
function determineReturnsPeriods(returnCycle) {
return [
{
startDate: _startDate(returnCycle.startDate, returnPeriodDates.quarterOne),
endDate: _endDate(returnCycle.startDate, returnPeriodDates.quarterOne),
id: returnCycle.id,
dueDate: _dueDate(returnCycle.startDate, returnPeriodDates.quarterOne)
},
{
startDate: _startDate(returnCycle.startDate, returnPeriodDates.quarterTwo),
endDate: _endDate(returnCycle.startDate, returnPeriodDates.quarterTwo),
id: returnCycle.id,
dueDate: _dueDate(returnCycle.startDate, returnPeriodDates.quarterTwo)
},
{
startDate: _startDateQuarterThree(returnCycle.startDate, returnPeriodDates.quarterThree),
endDate: _endDateQuarterThree(returnCycle.startDate, returnPeriodDates.quarterThree),
id: returnCycle.id,
dueDate: _dueQuarterThree(returnCycle.startDate, returnPeriodDates.quarterThree)
},
{
startDate: _startDate(returnCycle.endDate, returnPeriodDates.quarterFour),
endDate: _endDate(returnCycle.endDate, returnPeriodDates.quarterFour),
id: returnCycle.id,
dueDate: _dueDate(returnCycle.endDate, returnPeriodDates.quarterFour)
}
]
}

/**
* Determine return periods.
*
Expand All @@ -20,7 +60,7 @@ const { returnPeriodDates } = require('./static-lookups.lib.js')
*
* @returns {object} An object containing calculated dates for all return periods
*/
function determineReturnsPeriods(determinationDate = new Date()) {
function determineUpcomingReturnsPeriods(determinationDate = new Date()) {
return {
allYear: {
startDate: _cycleStartDate(determinationDate, returnPeriodDates.allYear),
Expand All @@ -43,14 +83,14 @@ function determineReturnsPeriods(determinationDate = new Date()) {
dueDate: _dueDate(determinationDate, returnPeriodDates.quarterTwo)
},
quarterThree: {
startDate: _startDate(determinationDate, returnPeriodDates.quarterThree),
endDate: _endDate(determinationDate, returnPeriodDates.quarterThree),
dueDate: _dueDate(determinationDate, returnPeriodDates.quarterThree)
startDate: _startDateQuarterThree(determinationDate, returnPeriodDates.quarterThree),
endDate: _endDateQuarterThree(determinationDate, returnPeriodDates.quarterThree),
dueDate: _dueQuarterThree(determinationDate, returnPeriodDates.quarterThree)
},
quarterFour: {
startDate: _startDateQuarterFour(determinationDate, returnPeriodDates.quarterFour),
endDate: _endDateQuarterFour(determinationDate, returnPeriodDates.quarterFour),
dueDate: _dueQuarterFour(determinationDate, returnPeriodDates.quarterFour)
startDate: _startDate(determinationDate, returnPeriodDates.quarterFour),
endDate: _endDate(determinationDate, returnPeriodDates.quarterFour),
dueDate: _dueDate(determinationDate, returnPeriodDates.quarterFour)
}
}
}
Expand Down Expand Up @@ -145,29 +185,28 @@ function _isDue(determinationDate, period) {
}

/**
* Calculates the start date for Quarter Four based on the determination date.
* Calculates the start date for Quarter Three based on the determination date.
*
* The start date is determined using the period's start day and month. The year for the start date
* is always set to the year of the provided determination date, regardless of its specific value.
*
*
* @param {Date} determinationDate - The base date used to calculate the start date.
* @param {object} period - The period object containing the start date information.
*
* @returns {Date} A `Date` object representing the start date of Quarter Four.
* @returns {Date} A `Date` object representing the start date of Quarter Three.
* @private
*/
function _startDateQuarterFour(determinationDate, period) {
function _startDateQuarterThree(determinationDate, period) {
const periodStartDay = period.startDate.day
const periodStartMonth = period.startDate.month + 1

const year = _newYearElapsedQuarterFour(determinationDate, period)
const year = _newYearElapsedQuarterThree(determinationDate, period)

return new Date(`${year}-${periodStartMonth}-${periodStartDay}`)
}

/**
* Calculates the end date for Quarter Four based on the determination date.
* Calculates the end date for Quarter Three based on the determination date.
*
* The end date is determined using the period's end day and month. If the determination date
* falls on or before December 31 of the current year, the end year is set to the current year.
Expand All @@ -177,20 +216,20 @@ function _startDateQuarterFour(determinationDate, period) {
* @param {Date} determinationDate - The base date used to calculate the end date.
* @param {Object} period - The period object containing the end date information.
*
* @returns {Date} A `Date` object representing the end date of Quarter Four.
* @returns {Date} A `Date` object representing the end date of Quarter Three.
* @private
*/
function _endDateQuarterFour(determinationDate, period) {
function _endDateQuarterThree(determinationDate, period) {
const periodStartDay = period.endDate.day
const periodStartMonth = period.endDate.month + 1

const year = _newYearElapsedQuarterFour(determinationDate, period)
const year = _newYearElapsedQuarterThree(determinationDate, period)

return new Date(`${year}-${periodStartMonth}-${periodStartDay}`)
}

/**
* Calculates the due date for Quarter Four, which spans into the next year.
* Calculates the due date for Quarter Three, which spans into the next year.
*
* The due date is always set in the following year relative to the provided determination date.
* For example, if the determination date is `2024-01-01`, the due date will be in `2025`,
Expand All @@ -199,34 +238,34 @@ function _endDateQuarterFour(determinationDate, period) {
* @param {Date} determinationDate - The base date used to calculate the due date.
* @param {object} period - The period object containing the due date information.
*
* @returns {Date} A `Date` object representing the due date of Quarter Four, always in the following year.
* @returns {Date} A `Date` object representing the due date of Quarter Three, always in the following year.
* @private
*/
function _dueQuarterFour(determinationDate, period) {
function _dueQuarterThree(determinationDate, period) {
const periodDueDay = period.dueDate.day
const periodDueMonth = period.dueDate.month + 1

const year = _newYearElapsedQuarterFourDueDate(determinationDate, period)
const year = _newYearElapsedQuarterThreeDueDate(determinationDate, period)

return new Date(`${year}-${periodDueMonth}-${periodDueDay}`)
}

/**
* Determines whether the new year has elapsed for Quarter Four based on the determination date.
* Determines whether the new year has elapsed for Quarter Three based on the determination date.
*
* This function calculates the year associated with Quarter Four by comparing the determination
* This function calculates the year associated with Quarter Three by comparing the determination
* date with the due date specified in the period. If the determination date is earlier than or equal
* to the due date for Quarter Four in the current year, the previous year is returned (as the quarter is still Due).
* to the due date for Quarter Three in the current year, the previous year is returned (as the quarter is still Due).
* Otherwise, the current year is returned.
*
* @param {Date} determinationDate - The base date used to determine the year for Quarter Four.
* @param {Date} determinationDate - The base date used to determine the year for Quarter Three.
* @param {object} period - The period object containing the due date information.
*
* @returns {number} The year associated with Quarter Four: the previous year if the determination date
* @returns {number} The year associated with Quarter Three: the previous year if the determination date
* is before or on the due date, otherwise the current year.
* @private
*/
function _newYearElapsedQuarterFour(determinationDate, period) {
function _newYearElapsedQuarterThree(determinationDate, period) {
const year = determinationDate.getFullYear()
const lastYear = year - 1

Expand All @@ -241,21 +280,21 @@ function _newYearElapsedQuarterFour(determinationDate, period) {
}

/**
* Determines the year associated with Quarter Four's due date based on the determination date.
* Determines the year associated with Quarter Three's due date based on the determination date.
*
* This function calculates the year for Quarter Four's due date by comparing the determination date
* This function calculates the year for Quarter Three's due date by comparing the determination date
* with the due date specified in the period. If the determination date is earlier than or equal to
* the due date in the current year, the current year is returned. Otherwise, the next year is returned
* (as the quarter is non longer due in the current year).
*
* @param {Date} determinationDate - The base date used to determine the year for Quarter Four's due date.
* @param {Date} determinationDate - The base date used to determine the year for Quarter Three's due date.
* @param {object} period - The period object containing the due date information.
*
* @returns {number} The year associated with Quarter Four's due date: the current year if the determination
* @returns {number} The year associated with Quarter Three's due date: the current year if the determination
* date is before or on the due date, otherwise the next year.
* @private
*/
function _newYearElapsedQuarterFourDueDate(determinationDate, period) {
function _newYearElapsedQuarterThreeDueDate(determinationDate, period) {
const year = determinationDate.getFullYear()
const nextYear = year + 1

Expand All @@ -279,7 +318,7 @@ function _newYearElapsedQuarterFourDueDate(determinationDate, period) {
* @returns {object[]} - An array of return periods
*/
function determineUpcomingReturnPeriods(determinationDate = new Date()) {
const returnPeriods = determineReturnsPeriods(determinationDate)
const returnPeriods = determineUpcomingReturnsPeriods(determinationDate)
const mappedReturnPeriods = _mapReturnsPeriods(returnPeriods)
return _sortByDueDate(mappedReturnPeriods)
}
Expand Down Expand Up @@ -352,5 +391,6 @@ function _cycleStartDate(determinationDate, period) {

module.exports = {
determineReturnsPeriods,
determineUpcomingReturnsPeriods,
determineUpcomingReturnPeriods
}
53 changes: 32 additions & 21 deletions app/lib/static-lookups.lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ const naldRegions = {

const organisationTypes = ['individual', 'limitedCompany', 'limitedLiabilityPartnership', 'publicLimitedCompany']

/**
* The start, end and due dates for each return cycle
*/
const returnCycleDates = {
allYear: {
dueDate: { day: 28, month: 3 },
Expand All @@ -39,6 +42,32 @@ const returnCycleDates = {
}
}

/**
* The start, end and due dates for each quarterly return period
*/
const quarterlyReturnPeriods = {
quarterOne: {
dueDate: { day: 28, month: 6 },
endDate: { day: 30, month: 5 },
startDate: { day: 1, month: 3 }
},
quarterTwo: {
dueDate: { day: 28, month: 9 },
endDate: { day: 30, month: 8 },
startDate: { day: 1, month: 6 }
},
quarterThree: {
dueDate: { day: 28, month: 0 },
endDate: { day: 31, month: 11 },
startDate: { day: 1, month: 9 }
},
quarterFour: {
dueDate: { day: 28, month: 3 },
endDate: { day: 31, month: 2 },
startDate: { day: 1, month: 0 }
}
}

/**
* An object defining the return periods / cycles with their respective start dates, end dates, and due dates.
*
Expand All @@ -61,26 +90,7 @@ const returnCycleDates = {
*/
const returnPeriodDates = {
...returnCycleDates,
quarterOne: {
dueDate: { day: 28, month: 3 },
endDate: { day: 31, month: 2 },
startDate: { day: 1, month: 0 }
},
quarterTwo: {
dueDate: { day: 28, month: 6 },
endDate: { day: 30, month: 5 },
startDate: { day: 1, month: 3 }
},
quarterThree: {
dueDate: { day: 28, month: 9 },
endDate: { day: 30, month: 8 },
startDate: { day: 1, month: 6 }
},
quarterFour: {
dueDate: { day: 28, month: 0 },
endDate: { day: 31, month: 11 },
startDate: { day: 1, month: 9 }
}
...quarterlyReturnPeriods
}

const returnRequirementFrequencies = {
Expand Down Expand Up @@ -142,5 +152,6 @@ module.exports = {
returnRequirementFrequencies,
returnRequirementReasons,
sources,
twoPartTariffReviewIssues
twoPartTariffReviewIssues,
quarterlyReturnPeriods
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ async function _fetch(returnCycle) {
.withGraphFetched('returnVersion')
.modifyGraph('returnVersion', (returnVersionBuilder) => {
returnVersionBuilder
.select(['endDate', 'id', 'reason', 'startDate'])
.select(['endDate', 'id', 'reason', 'startDate', 'quarterlyReturns'])
.withGraphFetched('licence')
.modifyGraph('licence', (licenceBuilder) => {
licenceBuilder
Expand Down
16 changes: 14 additions & 2 deletions app/services/return-logs/create-return-logs.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

const { timestampForPostgres } = require('../../lib/general.lib.js')
const { determineReturnsPeriods } = require('../../lib/return-periods.lib.js')
const GenerateReturnLogService = require('./generate-return-log.service.js')
const ReturnLogModel = require('../../models/return-log.model.js')

Expand Down Expand Up @@ -42,9 +43,20 @@ async function go(returnRequirement, returnCycle) {
* @private
*/
function _generateReturnLogs(returnRequirement, returnCycle) {
const returnLog = GenerateReturnLogService.go(returnRequirement, returnCycle)
const isQuarterlyReturn = returnRequirement.returnVersion.quarterlyReturns
const returnLogs = []

return [returnLog]
if (isQuarterlyReturn && returnCycle.startDate >= new Date('2025-04-01')) {
const quarterlyReturnPeriods = determineReturnsPeriods(returnCycle)

for (const quarterlyReturnPeriod of quarterlyReturnPeriods) {
returnLogs.push(GenerateReturnLogService.go(returnRequirement, quarterlyReturnPeriod))
}
} else {
returnLogs.push(GenerateReturnLogService.go(returnRequirement, returnCycle))
}

return returnLogs
}

async function _persistReturnLogs(returnLogs) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async function _fetch(licenceId, changeDate) {
.withGraphFetched('returnVersion')
.modifyGraph('returnVersion', (returnVersionBuilder) => {
returnVersionBuilder
.select(['endDate', 'id', 'reason', 'startDate'])
.select(['endDate', 'id', 'reason', 'startDate', 'quarterlyReturns'])
.withGraphFetched('licence')
.modifyGraph('licence', (licenceBuilder) => {
licenceBuilder
Expand Down
19 changes: 18 additions & 1 deletion test/fixtures/return-logs.fixture.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ function returnCycle(summer = false) {
*/
function returnCycles(numberOfCycles = 2) {
const cycles = [
{
id: '4c5ff4dc-dfe0-4693-9cb5-acdebf6f76b8',
startDate: new Date('2025-11-01'),
endDate: new Date('2026-10-31'),
dueDate: new Date('2026-11-28'),
summer: true,
submittedInWrls: true
},
{
id: '6889b98d-964f-4966-b6d6-bf511d6526a9',
startDate: new Date('2025-04-01'),
endDate: new Date('2026-03-31'),
dueDate: new Date('2026-04-28'),
summer: false,
submittedInWrls: true
},
{
id: '4c5ff4dc-dfe0-4693-9cb5-acdebf6f76b4',
startDate: new Date('2024-11-01'),
Expand Down Expand Up @@ -176,7 +192,8 @@ function returnRequirements() {
id: 'eb57737f-b309-49c2-9ab6-f701e3a6fd96',
naldRegionId: 4
}
}
},
quarterlyReturns: true
},
points: [
{
Expand Down
Loading
Loading