Skip to content

Commit

Permalink
Merge pull request #75 from icefoganalytics/elcc-57/additional-tombst…
Browse files Browse the repository at this point in the history
…one-fields-for-early-learning-centers

ELCC-57: Part 1: Additional Tombstone Fields for Early Learning Centers
  • Loading branch information
klondikemarlen authored Mar 11, 2024
2 parents c4d4cf8 + 5d1bc95 commit 28f50fc
Show file tree
Hide file tree
Showing 22 changed files with 808 additions and 369 deletions.
41 changes: 41 additions & 0 deletions api/src/controllers/centres-controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { isNil } from "lodash"

import BaseController from "./base-controller"

import { Centre } from "@/models"
import { CentreServices } from "@/services"

export class CentresController extends BaseController {
async create() {
try {
const centre = await CentreServices.create(this.request.body, {
currentUser: this.currentUser,
})
return this.response.status(201).json({ centre })
} catch (error) {
return this.response.status(422).json({ message: `Centre creation failed: ${error}` })
}
}

async update() {
const centre = await this.loadCentre()
if (isNil(centre)) {
return this.response.status(404).json({ message: "Centre not found." })
}

try {
const updatedCentre = await CentreServices.update(centre, this.request.body, {
currentUser: this.currentUser,
})
return this.response.json({ centre: updatedCentre })
} catch (error) {
return this.response.status(422).json({ message: `Centre update failed: ${error}` })
}
}

private loadCentre(): Promise<Centre | null> {
return Centre.findByPk(this.params.centreId)
}
}

export default CentresController
1 change: 1 addition & 0 deletions api/src/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { CentresController } from "./centres-controller"
export { EmployeeBenefitsController } from "./employee-benefits-controller"
export { EmployeeWageTiersController } from "./employee-wage-tiers-controller"
export { FiscalPeriodsController } from "./fiscal-periods-controller"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { DataTypes } from "sequelize"

import type { Migration } from "@/db/umzug"

export const up: Migration = async ({ context: queryInterface }) => {
await queryInterface.addColumn("centres", "license_holder_name", {
type: DataTypes.STRING(100),
allowNull: true,
})
await queryInterface.addColumn("centres", "contact_name", {
type: DataTypes.STRING(100),
allowNull: true,
})
await queryInterface.addColumn("centres", "physical_address", {
type: DataTypes.STRING(250),
allowNull: true,
})
await queryInterface.addColumn("centres", "mailing_address", {
type: DataTypes.STRING(250),
allowNull: true,
})
await queryInterface.addColumn("centres", "email", {
type: DataTypes.STRING(100),
allowNull: true,
})
await queryInterface.addColumn("centres", "alt_email", {
type: DataTypes.STRING(100),
allowNull: true,
})
await queryInterface.addColumn("centres", "phone_number", {
type: DataTypes.STRING(20),
allowNull: true,
})
await queryInterface.addColumn("centres", "alt_phone_number", {
type: DataTypes.STRING(20),
allowNull: true,
})
await queryInterface.addColumn("centres", "fax_number", {
type: DataTypes.STRING(20),
allowNull: true,
})
await queryInterface.addColumn("centres", "vendor_identifier", {
type: DataTypes.STRING(20),
allowNull: true,
})
await queryInterface.addColumn("centres", "is_first_nation_program", {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
})
await queryInterface.addColumn("centres", "inspector_name", {
type: DataTypes.STRING(100),
allowNull: true,
})
await queryInterface.addColumn("centres", "neighborhood", {
type: DataTypes.STRING(100),
allowNull: true,
})

await queryInterface.addColumn("centres", "region", {
type: DataTypes.STRING(100),
allowNull: true,
})
}

export const down: Migration = async ({ context: queryInterface }) => {
await queryInterface.removeColumn("centres", "licenseHolderName")
await queryInterface.removeColumn("centres", "contactName")
await queryInterface.removeColumn("centres", "physicalAddress")
await queryInterface.removeColumn("centres", "mailingAddress")
await queryInterface.removeColumn("centres", "email")
await queryInterface.removeColumn("centres", "altEmail")
await queryInterface.removeColumn("centres", "phoneNumber")
await queryInterface.removeColumn("centres", "altPhoneNumber")
await queryInterface.removeColumn("centres", "faxNumber")
await queryInterface.removeColumn("centres", "vendorId")
await queryInterface.removeColumn("centres", "isFirstNationProgram")
await queryInterface.removeColumn("centres", "inspectorName")
await queryInterface.removeColumn("centres", "neighborhood")
await queryInterface.removeColumn("centres", "region")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { DataTypes } from "sequelize"

import type { Migration } from "@/db/umzug"

import { Centre } from "@/models"

export const up: Migration = async ({ context: queryInterface }) => {
await Centre.update({ region: Centre.Regions.WHITEHORSE }, { where: { region: null } })

await queryInterface.changeColumn("centres", "region", {
type: DataTypes.STRING(100),
allowNull: false,
})
}

export const down: Migration = async ({ context: queryInterface }) => {
await queryInterface.changeColumn("centres", "region", {
type: DataTypes.STRING(100),
allowNull: true,
})
}
110 changes: 98 additions & 12 deletions api/src/models/centre.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,53 @@ import {
HasManySetAssociationsMixin,
InferAttributes,
InferCreationAttributes,
Model,
NonAttribute,
} from "sequelize"

import sequelize from "@/db/db-client"
import CentreFundingPeriod from "@/models/centre-funding-period"
import FundingSubmissionLineJson from "@/models/funding-submission-line-json"
import BaseModel from "@/models/base-model"

export enum CentreStatus {
// Keep in sync with web/src/api/centres-api.ts
export enum CentreRegions {
WHITEHORSE = "whitehorse",
COMMUNITIES = "communities",
}

// TODO: normalize status to snake_case
export enum CentreStatuses {
ACTIVE = "Active",
INACTIVE = "Inactive",
UP_TO_DATE = "Up to date",
}

export class Centre extends Model<InferAttributes<Centre>, InferCreationAttributes<Centre>> {
export class Centre extends BaseModel<InferAttributes<Centre>, InferCreationAttributes<Centre>> {
static readonly Regions = CentreRegions
static readonly Statuses = CentreStatuses

declare id: CreationOptional<number>
declare name: string
declare license: string | null
declare community: string
declare region: string
declare status: string
declare hotMeal: boolean | null
declare licensedFor: number | null // licensed for xx number of children
declare lastSubmission: Date | null
declare isFirstNationProgram: boolean
declare license: CreationOptional<string | null>
declare hotMeal: CreationOptional<boolean | null>
declare licensedFor: CreationOptional<number | null> // licensed for xx number of children
declare licenseHolderName: CreationOptional<string | null>
declare contactName: CreationOptional<string | null>
declare physicalAddress: CreationOptional<string | null>
declare mailingAddress: CreationOptional<string | null>
declare email: CreationOptional<string | null>
declare altEmail: CreationOptional<string | null>
declare phoneNumber: CreationOptional<string | null>
declare altPhoneNumber: CreationOptional<string | null>
declare faxNumber: CreationOptional<string | null>
declare vendorIdentifier: CreationOptional<string | null>
declare inspectorName: CreationOptional<string | null>
declare neighborhood: CreationOptional<string | null>
declare lastSubmission: CreationOptional<Date | null>
declare createdAt: CreationOptional<Date>
declare updatedAt: CreationOptional<Date>

Expand Down Expand Up @@ -138,21 +164,33 @@ Centre.init(
type: DataTypes.STRING(200),
allowNull: false,
},
license: {
type: DataTypes.STRING(255),
allowNull: true,
},
community: {
type: DataTypes.STRING(255),
allowNull: false,
},
isFirstNationProgram: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
},
region: {
type: DataTypes.STRING(100),
allowNull: false,
validate: {
isIn: [Object.values(CentreRegions)],
},
},
status: {
type: DataTypes.STRING(255),
allowNull: false,
validate: {
isIn: [Object.values(CentreStatus)],
isIn: [Object.values(CentreStatuses)],
},
},
license: {
type: DataTypes.STRING(255),
allowNull: true,
},
hotMeal: {
type: DataTypes.BOOLEAN,
allowNull: true,
Expand All @@ -161,6 +199,54 @@ Centre.init(
type: DataTypes.INTEGER,
allowNull: true,
},
licenseHolderName: {
type: DataTypes.STRING(100),
allowNull: true,
},
contactName: {
type: DataTypes.STRING(100),
allowNull: true,
},
physicalAddress: {
type: DataTypes.STRING(250),
allowNull: true,
},
mailingAddress: {
type: DataTypes.STRING(250),
allowNull: true,
},
email: {
type: DataTypes.STRING(100),
allowNull: true,
},
altEmail: {
type: DataTypes.STRING(100),
allowNull: true,
},
phoneNumber: {
type: DataTypes.STRING(20),
allowNull: true,
},
altPhoneNumber: {
type: DataTypes.STRING(20),
allowNull: true,
},
faxNumber: {
type: DataTypes.STRING(20),
allowNull: true,
},
vendorIdentifier: {
type: DataTypes.STRING(20),
allowNull: true,
},
inspectorName: {
type: DataTypes.STRING(100),
allowNull: true,
},
neighborhood: {
type: DataTypes.STRING(100),
allowNull: true,
},
lastSubmission: {
type: DataTypes.DATEONLY,
allowNull: true,
Expand Down
4 changes: 4 additions & 0 deletions api/src/routes/api-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Router, type Request, type Response } from "express"

import { checkJwt, autheticateAndLoadUser } from "@/middleware/authz.middleware"
import {
CentresController,
EmployeeBenefitsController,
EmployeeWageTiersController,
FiscalPeriodsController,
Expand All @@ -15,6 +16,9 @@ export const apiRouter = Router()
// TODO: move all routing logic to this file, and move all route actions into controllers
apiRouter.use("/api", checkJwt, autheticateAndLoadUser)

apiRouter.route("/api/centres").post(CentresController.create)
apiRouter.route("/api/centres/:centreId").patch(CentresController.update)

apiRouter.route("/api/payments").get(PaymentsController.index).post(PaymentsController.create)
apiRouter
.route("/api/payments/:paymentId")
Expand Down
6 changes: 6 additions & 0 deletions api/src/routes/centre-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ centreRouter.get("/", async (req: Request, res: Response) => {
}
})

/**
* @deprecated prefer /api/centres -> CentresController#create
*/
centreRouter.post("/", RequireAdmin, async (req: Request, res: Response) => {
// TODO: figure out how to push this logic into the authentication layer
if (!(req.user instanceof User)) {
Expand Down Expand Up @@ -104,6 +107,9 @@ centreRouter.post("/:id/fiscal-year", async (req: Request, res: Response) => {
})
})

/**
* @deprecated prefer /api/centres/:centreId -> CentresController#update
*/
centreRouter.put("/:id", RequireAdmin, async (req: Request, res: Response) => {
// TODO: figure out how to push this logic into the authentication layer
if (!(req.user instanceof User)) {
Expand Down
6 changes: 4 additions & 2 deletions api/tests/factories/centre-factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Factory } from "fishery"
import { faker } from "@faker-js/faker"

import { Centre } from "@/models"
import { CentreStatus } from "@/models/centre"
import { CentreStatuses } from "@/models/centre"

const yukonCommunities = [
"Carmacks",
Expand Down Expand Up @@ -33,7 +33,9 @@ export const centreFactory = Factory.define<Centre>(({ sequence, onCreate }) =>
null,
]),
community: faker.helpers.arrayElement(yukonCommunities),
status: faker.helpers.objectValue(CentreStatus),
region: faker.helpers.enumValue(Centre.Regions),
isFirstNationProgram: faker.datatype.boolean({ probability: 0.3 }),
status: faker.helpers.objectValue(CentreStatuses),
hotMeal: faker.helpers.arrayElement([true, false, null]),
licensedFor: faker.helpers.arrayElement([faker.number.int({ min: 1, max: 100 }), null]),
lastSubmission: faker.helpers.arrayElement([faker.date.recent(), null]),
Expand Down
3 changes: 2 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"start": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
"test": "vitest"
"test": "vitest",
"check-types": "vue-tsc --noEmit"
},
"dependencies": {
"@auth0/auth0-vue": "^2.0.0",
Expand Down
Loading

0 comments on commit 28f50fc

Please sign in to comment.