bex-twn/src/industry-change-application/industry-change-application...

157 lines
4.6 KiB
TypeScript

import {
BadRequestException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import {
ApplicationStatus,
ObjectStatus,
ResidentStatus,
} from 'src/enums/status.enum';
import { TypeOfRegistration } from 'src/enums/type-of-registration.enums';
import { ResidentService } from 'src/resident/resident.service';
import { takeMongoObject, equate, take } from 'src/utility';
import { ListQueryDto } from './dtos/list-query.dto';
import { RegisterIndustryChangeApplicationDto } from './dtos/register-industry-change-application.dto';
import {
IndustryChangeApplication,
IndustryChangeApplicationDocument,
} from './schemas/IndustryChangeApplication.schema';
const requestedFields = [
'industry',
'willWorkInPhysicalJurisdiction',
'regulatoryElection',
'regulatoryElectionSub',
];
const fieldsToExpose = [
'id',
'residentSub',
'current',
'requested',
'status',
'submittedAt',
'decision',
'objectStatus',
];
@Injectable()
export class IndustryChangeApplicationService {
constructor(
@InjectModel(IndustryChangeApplication.name)
private applicationModel: Model<IndustryChangeApplicationDocument>,
private resident: ResidentService,
) {}
async getAll(options: ListQueryDto) {
const getResident = await this.resident.getResidentBySub(
options.residentSub,
);
if (!getResident) {
throw new NotFoundException('Resident not found');
}
return this.applicationModel.find({
residentSub: options.residentSub,
status: {
$in: options.statuses || Object.values(ApplicationStatus),
},
});
}
async getById(id: string) {
return this.applicationModel.findById(id);
}
async create(data: RegisterIndustryChangeApplicationDto, token: string) {
// This might be possible to turn into a custom validator for class-validator
if (
data.willWorkInPhysicalJurisdiction === false &&
(!!data.industry ||
!!data.regulatoryElection ||
!!data.regulatoryElectionSub)
) {
throw new BadRequestException(
'industry, regulatoryElection and regulatoryElectionSub are not allowed when willWorkInPhysicalJurisdiction is false',
);
}
const getResident = await this.resident.getResidentBySub(data.residentSub);
if (!getResident) {
throw new BadRequestException('Resident not found');
}
if (getResident.status !== ResidentStatus.ACTIVE) {
throw new BadRequestException('Resident must be active!');
}
if (
![TypeOfRegistration.E_RESIDENCY, TypeOfRegistration.RESIDENCY].includes(
getResident.typeOfRegistration,
)
) {
throw new BadRequestException(
'Resident must be either an E-resident or a resident',
);
}
if (
equate(data, getResident, requestedFields).length ===
requestedFields.length
) {
throw new BadRequestException('Cannot request what is already the case.');
}
const status =
data.willWorkInPhysicalJurisdiction === true
? ApplicationStatus.IN_REVIEW
: ApplicationStatus.APPROVED;
const newApplication = new this.applicationModel({
residentSub: getResident.sub,
current: take(takeMongoObject(getResident), requestedFields),
requested: take(data, requestedFields),
status,
submittedAt: new Date(),
createdBy: token ?? 'no token provided for testing',
});
return newApplication.save();
}
async markDeleted(id: string, token: string) {
const findApplication = await this.applicationModel.findById(id);
if (!findApplication) {
throw new NotFoundException('Application was not found');
}
if (findApplication.status !== ApplicationStatus.IN_REVIEW) {
throw new BadRequestException(
'Only applications which are currently in review can be deleted.',
);
}
if (findApplication.objectStatus === ObjectStatus.DELETED) {
throw new BadRequestException('The object has already been deleted.');
}
findApplication.objectStatus = ObjectStatus.DELETED;
findApplication.updatedBy = token || 'no token provided for testing';
return findApplication.save();
}
// I wrote this because I could not for the life of me get class-transformer to
// play along with mongo documents. I do not have experience with either, so this
// was a last ditch effort.
makeReadable(input: IndustryChangeApplication | IndustryChangeApplication[]) {
return Array.isArray(input)
? input.map((object) => take(takeMongoObject(object), fieldsToExpose))
: take(takeMongoObject(input), fieldsToExpose);
}
}