Skip to content

Commit

Permalink
feat: ORV2-2196 - Add pendingPermits Optional query param to GET Appl…
Browse files Browse the repository at this point in the history
…ications. (#1303)
  • Loading branch information
praju-aot authored Apr 3, 2024
1 parent 9f41784 commit 5b4a6e3
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 82 deletions.
74 changes: 36 additions & 38 deletions frontend/src/features/permits/apiManager/permitsAPI.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { AxiosResponse } from "axios";

import { DATE_FORMATS, toLocal } from "../../../common/helpers/formatDate";
import { IssuePermitsResponse, PermitListItem, PermitResponseData } from "../types/permit";
import {
IssuePermitsResponse,
PermitListItem,
PermitResponseData,
} from "../types/permit";
import { PermitHistory } from "../types/PermitHistory";
import { getPermitTypeName } from "../types/PermitType";
import { removeEmptyIdsFromPermitsActionResponse } from "../helpers/mappers";
Expand Down Expand Up @@ -105,9 +109,7 @@ export const getApplicationsInProgress = async ({
take = 10,
searchString,
orderBy = [],
}: PaginationAndFilters): Promise<
PaginatedResponse<ApplicationListItem>
> => {
}: PaginationAndFilters): Promise<PaginatedResponse<ApplicationListItem>> => {
const companyId = getCompanyIdFromSession();
const applicationsURL = new URL(APPLICATIONS_API_ROUTES.GET);
if (companyId) {
Expand All @@ -117,6 +119,8 @@ export const getApplicationsInProgress = async ({
// API pagination index starts at 1. Hence page + 1.
applicationsURL.searchParams.set("page", (page + 1).toString());
applicationsURL.searchParams.set("take", take.toString());
//For the time being, we are hardcoding false as we do not want pendingPermits to be displayed in AIP tab
applicationsURL.searchParams.set("pendingPermits", false.toString());
if (searchString) {
applicationsURL.searchParams.set("searchString", searchString);
}
Expand All @@ -132,35 +136,31 @@ export const getApplicationsInProgress = async ({
) as PaginatedResponse<ApplicationListItem>;
return paginatedResponseObject;
})
.then(
(
paginatedApplications: PaginatedResponse<ApplicationListItem>,
) => {
const applicationsWithDateTransformations =
paginatedApplications.items.map((application) => {
return {
...application,
permitType: getPermitTypeName(application.permitType) as string,
createdDateTime: toLocal(
application?.createdDateTime,
DATE_FORMATS.DATETIME_LONG_TZ,
),
updatedDateTime: toLocal(
application?.updatedDateTime,
DATE_FORMATS.DATETIME_LONG_TZ,
),
startDate: toLocal(
application?.startDate,
DATE_FORMATS.DATEONLY_SHORT_NAME,
),
} as ApplicationListItem;
});
return {
...paginatedApplications,
items: applicationsWithDateTransformations,
};
},
);
.then((paginatedApplications: PaginatedResponse<ApplicationListItem>) => {
const applicationsWithDateTransformations =
paginatedApplications.items.map((application) => {
return {
...application,
permitType: getPermitTypeName(application.permitType) as string,
createdDateTime: toLocal(
application?.createdDateTime,
DATE_FORMATS.DATETIME_LONG_TZ,
),
updatedDateTime: toLocal(
application?.updatedDateTime,
DATE_FORMATS.DATETIME_LONG_TZ,
),
startDate: toLocal(
application?.startDate,
DATE_FORMATS.DATEONLY_SHORT_NAME,
),
} as ApplicationListItem;
});
return {
...paginatedApplications,
items: applicationsWithDateTransformations,
};
});

return applications;
};
Expand Down Expand Up @@ -501,13 +501,13 @@ export const voidPermit = async (voidPermitParams: {
* @returns Response with amended permit application, or error if failed
*/
export const amendPermit = async (
formData: AmendPermitFormData
formData: AmendPermitFormData,
): Promise<AxiosResponse<ApplicationResponseData>> => {
return await httpPOSTRequest(
PERMITS_API_ROUTES.AMEND,
replaceEmptyValuesWithNull({
// must convert application to ApplicationRequestData (dayjs fields to strings)
...serializeForCreateApplication(formData),
...serializeForCreateApplication(formData),
}),
);
};
Expand Down Expand Up @@ -547,9 +547,7 @@ export const resendPermit = async ({
return await httpPOSTRequest(
`${PERMITS_API_ROUTES.BASE}/${permitId}/${PERMITS_API_ROUTES.RESEND}`,
replaceEmptyValuesWithNull({
to: [
email,
],
to: [email],
fax,
}),
);
Expand Down
21 changes: 11 additions & 10 deletions vehicles/src/common/enum/application-status.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,18 @@ export const ACTIVE_APPLICATION_STATUS_FOR_ISSUANCE: ReadonlyArray<ApplicationSt
];

/**
* Application statuses to be considered for Application In Progress (AIP) Tab for Cv Client Users.
* Application statuses to be considered for Application In Progress (AIP) Tab for All Users.
*/
export const CVCLIENT_ACTIVE_APPLICATION_STATUS: ReadonlyArray<ApplicationStatus> =
[ApplicationStatus.IN_PROGRESS, ApplicationStatus.WAITING_PAYMENT];
export const ACTIVE_APPLICATION_STATUS: ReadonlyArray<ApplicationStatus> = [
ApplicationStatus.IN_PROGRESS,
ApplicationStatus.WAITING_PAYMENT,
];

/**
* Application statuses to be considered for Application In Progress (AIP) Tab for Staff Users.
* Application statuses including Application In Progress (AIP) and Pending Permits/Applications
*/
export const IDIR_ACTIVE_APPLICATION_STATUS: ReadonlyArray<ApplicationStatus> =
[
ApplicationStatus.IN_PROGRESS,
ApplicationStatus.WAITING_PAYMENT,
//ApplicationStatus.CANCELLED, //! Discovery Pending
];
export const ALL_APPLICATION_STATUS: ReadonlyArray<ApplicationStatus> = [
ApplicationStatus.IN_PROGRESS,
ApplicationStatus.WAITING_PAYMENT,
ApplicationStatus.PAYMENT_COMPLETE,
];
20 changes: 0 additions & 20 deletions vehicles/src/common/helper/permit-application.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ import { callDatabaseSequence } from './database.helper';
import { PermitApplicationOrigin as PermitApplicationOriginEnum } from '../enum/permit-application-origin.enum';
import { PermitApprovalSource as PermitApprovalSourceEnum } from '../enum/permit-approval-source.enum';
import { randomInt } from 'crypto';
import {
ApplicationStatus,
IDIR_ACTIVE_APPLICATION_STATUS,
CVCLIENT_ACTIVE_APPLICATION_STATUS,
} from '../enum/application-status.enum';
import { IDIR_USER_AUTH_GROUP_LIST } from '../enum/user-auth-group.enum';
import { IUserJWT } from '../interface/user-jwt.interface';
import { doesUserHaveAuthGroup } from './auth.helper';

/**
* Fetches and resolves various types of names associated with a permit using cache.
Expand Down Expand Up @@ -197,15 +189,3 @@ export const generatePermitNumber = async (
const permitNumber = `P${approvalSourceId}-${sequence}-${randomNumber}${revision}`;
return permitNumber;
};

export const getActiveApplicationStatus = (currentUser: IUserJWT) => {
const applicationStatus: Readonly<ApplicationStatus[]> =
doesUserHaveAuthGroup(
currentUser.orbcUserAuthGroup,
IDIR_USER_AUTH_GROUP_LIST,
)
? IDIR_ACTIVE_APPLICATION_STATUS
: CVCLIENT_ACTIVE_APPLICATION_STATUS;

return applicationStatus;
};
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export class ApplicationController {
page: getApplicationQueryParamsDto.page,
take: getApplicationQueryParamsDto.take,
orderBy: getApplicationQueryParamsDto.orderBy,
pendingPermits: getApplicationQueryParamsDto.pendingPermits,
companyId: getApplicationQueryParamsDto.companyId,
userGUID: userGuid,
currentUser: currentUser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
NotFoundException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DataSource, Repository, SelectQueryBuilder } from 'typeorm';
import { Brackets, DataSource, Repository, SelectQueryBuilder } from 'typeorm';
import { CreateApplicationDto } from './dto/request/create-application.dto';
import { ReadApplicationDto } from './dto/response/read-application.dto';
import { Permit } from '../permit/entities/permit.entity';
Expand Down Expand Up @@ -50,7 +50,9 @@ import { ReadApplicationMetadataDto } from './dto/response/read-application-meta
import { doesUserHaveAuthGroup } from '../../../common/helper/auth.helper';
import { formatTemplateData } from '../../../common/helper/format-template-data.helper';
import {
ACTIVE_APPLICATION_STATUS,
ACTIVE_APPLICATION_STATUS_FOR_ISSUANCE,
ALL_APPLICATION_STATUS,
ApplicationStatus,
} from '../../../common/enum/application-status.enum';
import { IDP } from '../../../common/enum/idp.enum';
Expand All @@ -59,7 +61,6 @@ import {
fetchPermitDataDescriptionValuesFromCache,
generateApplicationNumber,
generatePermitNumber,
getActiveApplicationStatus,
} from '../../../common/helper/permit-application.helper';
import { INotificationDocument } from '../../../common/interface/notification-document.interface';
import { ReadFileDto } from '../../common/dto/response/read-file.dto';
Expand Down Expand Up @@ -241,6 +242,7 @@ export class ApplicationService {
page: number;
take: number;
orderBy?: string;
pendingPermits?: boolean;
companyId?: number;
userGUID?: string;
currentUser?: IUserJWT;
Expand All @@ -249,6 +251,7 @@ export class ApplicationService {
const applicationsQB = this.buildApplicationQuery(
findAllApplicationsOptions.currentUser,
findAllApplicationsOptions.companyId,
findAllApplicationsOptions.pendingPermits,
findAllApplicationsOptions.userGUID,
);
// total number of items
Expand Down Expand Up @@ -315,6 +318,7 @@ export class ApplicationService {
private buildApplicationQuery(
currentUser: IUserJWT,
companyId?: number,
pendingPermits?: boolean,
userGUID?: string,
): SelectQueryBuilder<Permit> {
let permitsQuery = this.permitRepository
Expand All @@ -335,13 +339,30 @@ export class ApplicationService {
});
}

//Filter by application status
if (currentUser) {
// Handle pending permits query condition
if (pendingPermits) {
permitsQuery = permitsQuery.andWhere(
'permit.permitStatus IN (:...statuses)',
{
statuses: getActiveApplicationStatus(currentUser),
},
new Brackets((qb) => {
qb.where('permit.permitStatus IN (:...statuses)', {
statuses: [ApplicationStatus.PAYMENT_COMPLETE],
});
}),
);
} else if (pendingPermits === false) {
permitsQuery = permitsQuery.andWhere(
new Brackets((qb) => {
qb.where('permit.permitStatus IN (:...statuses)', {
statuses: ACTIVE_APPLICATION_STATUS,
});
}),
);
} else if (pendingPermits === undefined) {
permitsQuery = permitsQuery.andWhere(
new Brackets((qb) => {
qb.where('permit.permitStatus IN (:...statuses)', {
statuses: ALL_APPLICATION_STATUS,
});
}),
);
}

Expand Down Expand Up @@ -788,10 +809,6 @@ export class ApplicationService {
companyId: number,
currentUser: IUserJWT,
): Promise<DeleteDto> {
// Retrieve active application statuses based on the current user
const applicationStatus: ReadonlyArray<ApplicationStatus> =
getActiveApplicationStatus(currentUser);

// Build query to find applications matching certain criteria like company ID, application status, and undefined permit numbers
const applicationsQB = this.permitRepository
.createQueryBuilder('permit')
Expand All @@ -802,7 +819,7 @@ export class ApplicationService {
companyId: companyId,
})
.andWhere('permit.permitStatus IN (:...applicationStatus)', {
applicationStatus: applicationStatus,
applicationStatus: ACTIVE_APPLICATION_STATUS,
})
.andWhere('permit.permitNumber IS NULL');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { ApiProperty } from '@nestjs/swagger';
import { Type, Transform } from 'class-transformer';
import {
IsOptional,
IsBoolean,
IsString,
Length,
IsNumber,
Validate,
} from 'class-validator';
import { Type } from 'class-transformer';
import { OrderByConstraint } from '../../../../../../common/constraint/orderby.constraint';
import { PageOptionsDto } from '../../../../../../common/dto/paginate/page-options';
import { ApplicationOrderBy } from '../../../../../../common/enum/orderBy.enum';
Expand Down Expand Up @@ -43,4 +44,17 @@ export class GetApplicationQueryParamsDto extends PageOptionsDto {
@IsString()
@Length(1, 150)
readonly orderBy?: string;

@ApiProperty({
description:
'Setting to false confines the search to only applications awaiting payment, while true limits it to applications that have received payment but are awaiting issuance. If unspecified, all applications, including those awaiting issuance, are also fetched.',
example: true,
required: false,
})
@IsOptional()
@Transform(({ obj, key }: { obj: Record<string, unknown>; key: string }) => {
return obj[key] === 'true' ? true : obj[key] === 'false' ? false : obj[key];
})
@IsBoolean()
pendingPermits?: boolean;
}

0 comments on commit 5b4a6e3

Please sign in to comment.