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 return cycle #1353

Merged
merged 17 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions app/models/return-cycle.model.js
robertparkinson marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict'

/**
* Model for return_cycles (returns.return_cycle)
* @module ReturnCycleModel
*/

const { Model } = require('objection')

const BaseModel = require('./base.model.js')

class ReturnCycleModel extends BaseModel {
static get tableName () {
return 'returnCycles'
}

static get relationMappings () {
return {
returnLogs: {
relation: Model.HasManyRelation,
modelClass: 'return-log.model',
join: {
from: 'returnCycles.id',
to: 'returnLogs.returnCycleId'
}
}
}
}
}

module.exports = ReturnCycleModel
8 changes: 8 additions & 0 deletions app/models/return-log.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ class ReturnLogModel extends BaseModel {
from: 'returnLogs.id',
to: 'returnSubmissions.returnLogId'
}
},
returnCycle: {
relation: Model.HasOneRelation,
modelClass: 'return-cycle.model',
join: {
from: 'returnLogs.returnCycleId',
to: 'returnCycles.id'
}
}
}
}
Expand Down
83 changes: 83 additions & 0 deletions app/services/jobs/return-logs/fetch-return-cycle.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict'

/**
* Fetches the return cycle for the given date
* @module FetchReturnCycleService
*/

const ReturnCycleModel = require('../../../models/return-cycle.model.js')

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

/**
* Given a date this service returns the return cycle for that date.
*
* @param {string} date - the date to find the return cycle for - YYYY-MM-DD
* @param {boolean} summer - which cycle to return - summer or winter and all year
*
* @returns {Promise<string>} the id of the return cycle
*/
async function go (date, summer) {
const _date = new Date(date)
const cycleStartDate = _cycleStartDateByDate(_date, summer)
const cycleEndDate = _cycleEndDateByDate(_date, summer)
const data = await _fetchReturnCycle(cycleStartDate, cycleEndDate, summer)

if (data) {
return data.id
}

return undefined
}

function _cycleEndDateByDate (date, summer) {
const year = date.getFullYear()
const month = date.getMonth()

if (summer) {
if (month >= returnCycleDates.summer.endDate.month) {
return `${year + 1}-10-31`
}

return `${year}-10-31`
}

if (month >= returnCycleDates.allYear.endDate.month) {
return `${year + 1}-03-31`
}

return `${year}-03-31`
}

function _cycleStartDateByDate (date, summer) {
const year = date.getFullYear()
const month = date.getMonth()

if (summer) {
if (month <= returnCycleDates.summer.startDate.month) {
return `${year - 1}-11-01`
}

return `${year - 1}-04-01`
}

if (month <= returnCycleDates.allYear.startDate.month) {
return `${year - 1}-04-01`
}

return `${year}-04-01`
}

async function _fetchReturnCycle (startDate, endDate, summer) {
return ReturnCycleModel.query()
.select(['id'])
.where('startDate', '>=', startDate)
.where('endDate', '<=', endDate)
.where('summer', summer)
.limit(1)
.first()
}

module.exports = {
go
}
48 changes: 48 additions & 0 deletions app/services/jobs/return-logs/generate-return-cycle.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use strict'

/**
* Generates the current return cycle either summer or all year depending on the passed in boolean.
* @module GenerateReturnCycleService
*/

const { cycleDueDateAsISO, cycleEndDateAsISO, cycleStartDateAsISO } = require('../../../lib/dates.lib.js')
const ReturnCycleModel = require('../../../models/return-cycle.model.js')

/**
* Creates the new entry in the return_cycle table and returns its id.
*
* @param {boolean} summer - are we running summer cycle or all year
*
* @returns {Promise<string>} the UUID of the return cycle that has been created
*/
async function go (summer) {
const data = _generateData(summer)
const returnCycle = await _createReturnCycle(data)

return returnCycle.id
}

function _createReturnCycle (returnCycle) {
return ReturnCycleModel.query()
.insert(returnCycle)
}

function _generateData (summer) {
const dueDate = cycleDueDateAsISO(summer)
const endDate = cycleEndDateAsISO(summer)
const startDate = cycleStartDateAsISO(summer)

return {
createdAt: new Date(),
dueDate,
endDate,
summer,
submittedInWrls: true,
startDate,
updatedAt: new Date()
}
}

module.exports = {
go
}
9 changes: 6 additions & 3 deletions app/services/jobs/return-logs/generate-return-logs.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ const {
* Generates the payload for submission to the returns table.
*
* @param {Array} returnRequirements - the return requirements to be turned into return logs
* @param {string} returnCycleId - the UUID of the return cycle
*
* @returns {Promise<Array>} the array of return log payloads to be created in the database
*/
async function go (returnRequirements) {
async function go (returnRequirements, returnCycleId) {
const returnLogs = returnRequirements.map(async (requirements) => {
const startDate = _startDate(requirements.summer, requirements.returnVersion)
const endDate = _endDate(requirements.summer, requirements.returnVersion)
Expand All @@ -36,11 +37,12 @@ async function go (returnRequirements) {
id,
licenceRef: requirements.returnVersion.licence.licenceRef,
metadata,
returnCycleId,
returnsFrequency: requirements.reportingFrequency,
returnReference: requirements.legacyId.toString(),
startDate,
status: 'due',
source: 'WRLS',
returnReference: requirements.legacyId.toString()
source: 'WRLS'
}
})

Expand Down Expand Up @@ -138,6 +140,7 @@ function _metadataPoints (points) {
function _metadataPurposes (returnRequirementPurposes) {
return returnRequirementPurposes.map((returnRequirementPurpose) => {
return {
alias: returnRequirementPurpose.alias,
primary: {
code: returnRequirementPurpose.primaryPurpose.legacyId,
description: returnRequirementPurpose.primaryPurpose.description
Expand Down
12 changes: 11 additions & 1 deletion app/services/jobs/return-logs/process-return-logs.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
*/

const { calculateAndLogTimeTaken, currentTimeInNanoseconds } = require('../../../lib/general.lib.js')
const { formatDateObjectToISO } = require('../../../lib/dates.lib.js')
const FetchReturnCycleService = require('./fetch-return-cycle.service.js')
const FetchReturnRequirementsService = require('./fetch-return-requirements.service.js')
const GenerateReturnCycleService = require('./generate-return-cycle.service.js')
const GenerateReturnLogsService = require('./generate-return-logs.service.js')
const ReturnLogModel = require('../../../models/return-log.model.js')

Expand Down Expand Up @@ -37,8 +40,15 @@ async function go (cycle, licenceReference = null) {
try {
const startTime = currentTimeInNanoseconds()
const summer = cycle === 'summer'

let returnCycleId = await FetchReturnCycleService.go(formatDateObjectToISO(new Date()), summer)

if (!returnCycleId) {
returnCycleId = await GenerateReturnCycleService.go(summer)
}

const returnRequirements = await FetchReturnRequirementsService.go(summer, licenceReference)
const returnLogs = await GenerateReturnLogsService.go(returnRequirements)
const returnLogs = await GenerateReturnLogsService.go(returnRequirements, returnCycleId)

await _createReturnLogs(returnLogs)

Expand Down
35 changes: 35 additions & 0 deletions db/migrations/legacy/20240918125805_create-return-cycles-table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict'

const tableName = 'return_cycles'

exports.up = function (knex) {
return knex
.schema
.withSchema('returns')
.createTable(tableName, (table) => {
// Primary Key
table.uuid('return_cycle_id').primary().defaultTo(knex.raw('gen_random_uuid()'))

// Data
table.date('start_date').notNullable()
table.date('end_date').notNullable()
table.date('due_date').notNullable()
table.boolean('is_summer')
table.boolean('is_submitted_in_wrls')

// Legacy timestamps
// NOTE: They are not automatically set
table.timestamp('date_created').notNullable()
table.timestamp('date_updated')

// Constraints
table.unique(['start_date', 'end_date', 'is_summer'])
})
}

exports.down = function (knex) {
return knex
.schema
.withSchema('returns')
.dropTableIfExists(tableName)
}
26 changes: 26 additions & 0 deletions db/migrations/public/20240918125758_create-return-cycles-view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict'

const viewName = 'return_cycles'

exports.up = function (knex) {
return knex
.schema
.createView(viewName, (view) => {
view.as(knex('return_cycles').withSchema('returns').select([
'return_cycle_id AS id',
'start_date',
'end_date',
'due_date',
'is_summer AS summer',
'is_submitted_in_wrls AS submitted_in_wrls',
'date_created AS created_at',
'date_updated AS updated_at'
]))
})
}

exports.down = function (knex) {
return knex
.schema
.dropViewIfExists(viewName)
}
63 changes: 63 additions & 0 deletions db/migrations/public/20240918144353_alter-return-logs-view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
'use strict'

const viewName = 'return_logs'

exports.up = function (knex) {
return knex
.schema
.dropViewIfExists(viewName)
.createView(viewName, (view) => {
// NOTE: We have commented out unused columns from the source table
view.as(knex('returns').withSchema('returns').select([
'return_id AS id',
// 'regime', // always 'water'
// 'licence_type', // always 'abstraction'
'licence_ref',
'start_date',
'end_date',
'returns_frequency',
'status',
'source',
'metadata',
'received_date',
'return_requirement as return_reference',
'due_date',
'under_query',
// 'under_query_comment',
// 'is_test',
'return_cycle_id',
'created_at',
'updated_at'
]))
})
}

exports.down = function (knex) {
return knex
.schema
.dropViewIfExists(viewName)
.createView(viewName, (view) => {
// NOTE: We have commented out unused columns from the source table
view.as(knex('returns').withSchema('returns').select([
'return_id AS id',
// 'regime', // always 'water'
// 'licence_type', // always 'abstraction'
'licence_ref',
'start_date',
'end_date',
'returns_frequency',
'status',
// 'source', // always 'NALD'
'metadata',
'received_date',
'return_requirement',
'due_date',
'under_query',
// 'under_query_comment',
// 'is_test',
// 'return_cycle_id' // is populated but links to a table that does not appear to be used
'created_at',
'updated_at'
]))
})
}
20 changes: 20 additions & 0 deletions db/seeds/16-return-cycles.seed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict'

const { timestampForPostgres } = require('../../app/lib/general.lib.js')
const { data: returnCycles } = require('./data/return-cycles.js')
const ReturnCycleModel = require('../../app/models/return-cycle.model.js')

async function seed () {
for (const cycle of returnCycles) {
await _upsert(cycle)
}
}

async function _upsert (cycle) {
return ReturnCycleModel.query()
.insert({ ...cycle, createdAt: timestampForPostgres(), updatedAt: timestampForPostgres() })
}

module.exports = {
seed
}
Loading
Loading