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

Add multi-permits needed statistic #140

Merged
merged 1 commit into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions app/src/controllers/permit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ const controller = {
}
},

async listPermits(req: Request<{ activityId: string }>, res: Response, next: NextFunction) {
async listPermits(req: Request<never, { activityId?: string }>, res: Response, next: NextFunction) {
try {
const response = await permitService.listPermits(req.params.activityId);
const response = await permitService.listPermits(req.query?.activityId);
res.status(200).json(response);
} catch (e: unknown) {
next(e);
Expand Down
252 changes: 252 additions & 0 deletions app/src/db/migrations/20240718000000_007-rbac.ts

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions app/src/routes/v1/permit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ const router = express.Router();
router.use(requireSomeAuth);
router.use(requireSomeGroup);

// Permit list endpoint
router.get(
'/',
hasAuthorization(Resource.PERMIT, Action.READ),
permitValidator.listPermits,
(req: Request, res: Response, next: NextFunction): void => {
permitController.listPermits(req, res, next);
}
);

// Permit create endpoint
router.put(
'/',
Expand Down Expand Up @@ -46,16 +56,6 @@ router.delete(
}
);

// Permit list by activity endpoint
router.get(
'/list/:activityId',
hasAuthorization(Resource.PERMIT, Action.READ),
permitValidator.listPermits,
(req: Request, res: Response, next: NextFunction): void => {
permitController.listPermits(req, res, next);
}
);

// Permit types endpoint
router.get(
'/types',
Expand Down
6 changes: 3 additions & 3 deletions app/src/services/permit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,17 @@ const service = {

/**
* @function listPermits
* Retrieve a list of permits associated with a given activity
* Retrieve all permits if no activityId is provided, otherwise retrieve permits for a specific activity
* @param {string} activityId PCNS Activity ID
* @returns {Promise<Permit[]>} The result of running the findMany operation
*/
listPermits: async (activityId: string) => {
listPermits: async (activityId?: string) => {
const response = await prisma.permit.findMany({
include: {
permit_type: true
},
where: {
activity_id: activityId
activity_id: activityId ? activityId : undefined
},
orderBy: {
permit_type: {
Expand Down
4 changes: 2 additions & 2 deletions app/src/validators/permit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const schema = {
})
},
listPermits: {
params: Joi.object({
activityId: activityId
query: Joi.object({
activityId: Joi.string().min(8).max(8).allow(null)
})
},
updatePermit: {
Expand Down
8 changes: 4 additions & 4 deletions app/tests/unit/controllers/permit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ describe('listPermits', () => {
it('should return 200 if all good', async () => {
const now = new Date();
const req = {
params: { activityId: 'ACT_ID' },
query: { activityId: 'ACT_ID' },
currentContext: CURRENT_CONTEXT
};

Expand All @@ -275,14 +275,14 @@ describe('listPermits', () => {
await permitController.listPermits(req as any, res as any, next);

expect(listSpy).toHaveBeenCalledTimes(1);
expect(listSpy).toHaveBeenCalledWith(req.params.activityId);
expect(listSpy).toHaveBeenCalledWith(req.query.activityId);
expect(res.status).toHaveBeenCalledWith(200);
expect(res.json).toHaveBeenCalledWith(permitList);
});

it('calls next if the permit service fails to list permits', async () => {
const req = {
params: { activityId: 'ACT_ID' },
query: { activityId: 'ACT_ID' },
currentContext: CURRENT_CONTEXT
};

Expand All @@ -294,7 +294,7 @@ describe('listPermits', () => {
await permitController.listPermits(req as any, res as any, next);

expect(listSpy).toHaveBeenCalledTimes(1);
expect(listSpy).toHaveBeenCalledWith(req.params.activityId);
expect(listSpy).toHaveBeenCalledWith(req.query.activityId);
expect(res.status).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledTimes(1);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,13 @@ function isFinanciallySupported(data: Submission) {
style="min-width: 125px"
/>
<Column
field="user.fullName"
field="multiPermitsNeeded"
header="Multi-authorization project"
:sortable="true"
style="min-width: 125px"
/>
<Column
field="assignedTo"
header="Assigned to"
:sortable="true"
style="min-width: 200px"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ watch(
<td class="col-1 text-right">{{ statistics.total_submissions }}</td>
<td class="col-2 text-right">{{ getPercentage(statistics.total_submissions) }}%</td>
</tr>
<tr>
<td class="col-9">Multi-authorization projects</td>
<td class="col-1 text-right">{{ statistics.multi_permits_needed }}</td>
<td class="col-2 text-right">{{ getPercentage(statistics.multi_permits_needed) }}%</td>
</tr>
<tr>
<td class="col-9">
Submissions by range
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import SubmissionBringForwardCalendar from '@/components/housing/submission/Subm
import SubmissionListNavigator from '@/components/housing/submission/SubmissionListNavigator.vue';
import SubmissionStatistics from '@/components/housing/submission/SubmissionStatistics.vue';
import { Accordion, AccordionTab, TabPanel, TabView, useToast } from '@/lib/primevue';
import { enquiryService, noteService, submissionService } from '@/services';
import { enquiryService, noteService, permitService, submissionService } from '@/services';
import { useAuthNStore, useAuthZStore } from '@/store';
import { Action, Initiative, Resource, RouteName, StorageKey } from '@/utils/enums/application';
import { Action, BasicResponse, Initiative, Resource, RouteName, StorageKey } from '@/utils/enums/application';
import { SubmissionType } from '@/utils/enums/housing';
import { BringForwardType, IntakeStatus } from '@/utils/enums/housing';
import { formatDate } from '@/utils/formatters';

import type { Ref } from 'vue';
import type { BringForward, Enquiry, Statistics, Submission } from '@/types';
import type { BringForward, Enquiry, Permit, Statistics, Submission } from '@/types';

// Constants
const NOTES_TAB_INDEX = {
Expand All @@ -37,6 +37,7 @@ const bringForward: Ref<Array<BringForward>> = ref([]);
const enquiries: Ref<Array<Enquiry>> = ref([]);
const myBringForward: Ref<Array<BringForward>> = ref([]);
const myAssignedTo: Ref<Set<string>> = ref(new Set<string>());
const permits: Ref<Array<Permit>> = ref([]);
const loading: Ref<boolean> = ref(true);
const submissions: Ref<Array<Submission>> = ref([]);
const statistics: Ref<Statistics | undefined> = ref(undefined);
Expand Down Expand Up @@ -95,9 +96,10 @@ onMounted(async () => {
// To pull data from CHEFS
await submissionService.getSubmissions();

[enquiries.value, submissions.value, statistics.value, bringForward.value] = (
[enquiries.value, permits.value, submissions.value, statistics.value, bringForward.value] = (
await Promise.all([
enquiryService.getEnquiries(),
permitService.listPermits(),
submissionService.searchSubmissions({
includeUser: true,
intakeStatus: [IntakeStatus.ASSIGNED, IntakeStatus.COMPLETED, IntakeStatus.SUBMITTED]
Expand All @@ -108,6 +110,7 @@ onMounted(async () => {
).map((r) => r.data);

assignEnquiriesAndFullName();
assignMultiPermitsNeeded();

const profile = getProfile.value;

Expand Down Expand Up @@ -170,6 +173,19 @@ function assignEnquiriesAndFullName() {
});
}

// Set multiPermitsNeeded property of each submission to Yes/No (count)
// if the submission have more than one permit with needed Yes
function assignMultiPermitsNeeded() {
submissions.value.forEach((sub) => {
const multiPermitsNeededCount = permits.value.filter(
(x) => x.activityId === sub.activityId && x.needed?.toUpperCase() === BasicResponse.YES.toUpperCase()
).length;

if (multiPermitsNeededCount > 1) sub.multiPermitsNeeded = `${BasicResponse.YES} (${multiPermitsNeededCount})`;
else sub.multiPermitsNeeded = BasicResponse.NO;
});
}

watch(accordionIndex, () => {
if (accordionIndex.value !== null) {
window.sessionStorage.setItem(StorageKey.BF_ACCORDION_IDX, accordionIndex.value.toString());
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/services/permitService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ export default {
* @function listPermits
* @returns {Promise} An axios response
*/
async listPermits(activityId: string) {
return appAxios().get(`permit/list/${activityId}`);
async listPermits(activityId?: string) {
return appAxios().get('permit', { params: { activityId } });
},

/**
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/Statistics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export type Statistics = {
intake_submitted: number;
intake_assigned: number;
intake_completed: number;
multi_permits_needed: number;
state_new: number;
state_inprogress: number;
state_delayed: number;
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/Submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type Submission = {
projectLocationDescription: string;
singleFamilyUnits: string;
multiFamilyUnits: string;
multiPermitsNeeded: string;
otherUnitsDescription: string;
otherUnits: string;
hasRentalUnits: string;
Expand Down
2 changes: 1 addition & 1 deletion frontend/tests/unit/service/permitService.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('permitService test', () => {
it('calls get permit list', async () => {
await permitService.listPermits(TEST_ID);
expect(getSpy).toHaveBeenCalledTimes(1);
expect(getSpy).toHaveBeenCalledWith(`${PATH}/list/${TEST_ID}`);
expect(getSpy).toHaveBeenCalledWith(`${PATH}`, { params: { activityId: TEST_ID } });
});

it('calls get permit list with wrong ID', async () => {
Expand Down
Loading