diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index d27440a16..81df41ee8 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -140,6 +140,13 @@ export class AppModule { consumer.apply(HTTPLoggerMiddleware).exclude({ path: "", method: RequestMethod.ALL }).forRoutes("*"); consumer .apply(RequestTokenMiddleware) - .forRoutes("v1/code-table", "v1/case", "v1/configuration", "v1/complaint/search", "v1/complaint/map/search"); + .forRoutes( + "v1/code-table", + "v1/case", + "v1/configuration", + "v1/complaint/search", + "v1/complaint/map/search", + "v1/document/export-complaint", + ); } } diff --git a/backend/src/external_api/case_management.ts b/backend/src/external_api/case_management.ts index ff8dfceff..39f8c2a33 100644 --- a/backend/src/external_api/case_management.ts +++ b/backend/src/external_api/case_management.ts @@ -7,6 +7,136 @@ axios.interceptors.response.use(undefined, (error: AxiosError) => { return Promise.reject(error); }); +export const caseFileQueryFields: string = ` +{ + caseIdentifier + leadIdentifier + assessmentDetails { + actionNotRequired + actionJustificationCode + actionJustificationShortDescription + actionJustificationLongDescription + actionJustificationActiveIndicator + actions { + actionId + actor + date + actionCode + shortDescription + longDescription + activeIndicator + } + } + isReviewRequired + reviewComplete { + actor + date + actionCode + actionId + activeIndicator + } + preventionDetails { + actions { + actionId + actor + date + actionCode + shortDescription + longDescription + activeIndicator + } + } + note { + note + action { + actor + actionCode + date, + actionId, + activeIndicator + } + } + equipment { + id + typeCode + activeIndicator + address + xCoordinate + yCoordinate + createDate + actions { + actionId + actor + actionCode + date + } + wasAnimalCaptured + }, + subject { + id + species + sex + age + categoryLevel + conflictHistory + outcome + tags { + id + ear + identifier + + order + } + drugs { + id + + vial + drug + amountUsed + injectionMethod + reactions + + remainingUse + amountDiscarded + discardMethod + + order + } + actions { + actionId + actor + actionCode + date + } + order + } + decision { + id + schedule + scheduleLongDescription + sector + sectorLongDescription + discharge + dischargeLongDescription + nonCompliance + nonComplianceLongDescription + rationale + inspectionNumber + leadAgency + leadAgencyLongDescription + assignedTo + actionTaken + actionTakenLongDescription + actionTakenDate + } + authorization { + id + type + value + } +} +`; + export const get = (token, params?: {}) => { let config: AxiosRequestConfig = { headers: { diff --git a/backend/src/external_api/cdogs/cdogs.service.ts b/backend/src/external_api/cdogs/cdogs.service.ts index af6d1d157..08d14ef5b 100644 --- a/backend/src/external_api/cdogs/cdogs.service.ts +++ b/backend/src/external_api/cdogs/cdogs.service.ts @@ -123,10 +123,23 @@ export class CdogsService implements ExternalApiService { upload = async (apiToken: string, type: string, templateCode: string) => { const url = `${this.baseUri}/api/v2/template`; - const template = - type === "HWCR" - ? "templates/complaint/CDOGS-HWCR-COMPLAINT-TEMPLATE-v1.docx" - : "templates/complaint/CDOGS-ERS-COMPLAINT-TEMPLATE-v1.docx"; + let template: string; + + switch (templateCode) { + case "HWCTMPLATE": + template = "templates/complaint/CDOGS-HWCR-COMPLAINT-TEMPLATE-v1.docx"; + break; + case "ERSTMPLATE": + template = "templates/complaint/CDOGS-ERS-COMPLAINT-TEMPLATE-v1.docx"; + break; + case "CEEBTMPLAT": + template = "templates/complaint/CDOGS-CEEB-COMPLAINT-TEMPLATE-v1.docx"; + break; + default: + this.logger.error(`exception: unable to find template: ${template}`); + break; + } + const path = join(process.cwd(), template); try { @@ -166,7 +179,20 @@ export class CdogsService implements ExternalApiService { //-- render complaint to pdf //-- generate = async (documentName: string, data: any, type: COMPLAINT_TYPE): Promise => { - const templateCode = type === "HWCR" ? CONFIGURATION_CODES.HWCTMPLATE : CONFIGURATION_CODES.ERSTMPLATE; + //-- Determine template to use + let templateCode: string; + switch (type) { + case "HWCR": + templateCode = CONFIGURATION_CODES.HWCTMPLATE; + break; + case "ERS": + if (data.ownedBy === "EPO") { + templateCode = CONFIGURATION_CODES.CEEBTMPLATE; + } else { + templateCode = CONFIGURATION_CODES.ERSTMPLATE; + } + break; + } try { const apiToken = await this.authenticate(); diff --git a/backend/src/middleware/maps/automapper-entity-to-dto-maps.ts b/backend/src/middleware/maps/automapper-entity-to-dto-maps.ts index 4a1f6562e..7dcf9a5c7 100644 --- a/backend/src/middleware/maps/automapper-entity-to-dto-maps.ts +++ b/backend/src/middleware/maps/automapper-entity-to-dto-maps.ts @@ -1189,6 +1189,10 @@ export const mapWildlifeReport = (mapper: Mapper, tz: string = "America/Vancouve (destination) => destination.createdBy, mapFrom((source) => source.create_user_id), ), + forMember( + (destination) => destination.ownedBy, + mapFrom((source) => source.complaint_identifier.owned_by_agency_code.agency_code), + ), forMember( (destination) => destination.reportedOn, mapFrom((source) => { @@ -1487,6 +1491,10 @@ export const mapAllegationReport = (mapper: Mapper, tz: string = "America/Vancou (destination) => destination.createdBy, mapFrom((source) => source.create_user_id), ), + forMember( + (destination) => destination.ownedBy, + mapFrom((source) => source.complaint_identifier.owned_by_agency_code.agency_code), + ), forMember( (destination) => destination.reportedOn, mapFrom((source) => { diff --git a/backend/src/types/configuration-codes.ts b/backend/src/types/configuration-codes.ts index 179017f2e..f63b9244d 100644 --- a/backend/src/types/configuration-codes.ts +++ b/backend/src/types/configuration-codes.ts @@ -1,6 +1,7 @@ export const CONFIGURATION_CODES = { HWCTMPLATE: "HWCTMPLATE", ERSTMPLATE: "ERSTMPLATE", + CEEBTMPLATE: "CEEBTMPLAT", CDTABLEVER: "CDTABLEVER", DFLTPAGNUM: "DFLTPAGNUM", MAXFILESZ: "MAXFILESZ", diff --git a/backend/src/types/models/case-files/case-file.ts b/backend/src/types/models/case-files/case-file.ts index 82bb89fe4..3557ce8bc 100644 --- a/backend/src/types/models/case-files/case-file.ts +++ b/backend/src/types/models/case-files/case-file.ts @@ -4,6 +4,8 @@ import { EquipmentDetailsDto } from "./equipment/equipment-details"; import { Note } from "./supplemental-notes/note"; import { PreventionDetailsDto } from "./prevention-details"; import { FileReviewActionDto } from "./file-review-action"; +import { PermitSiteDto } from "./ceeb/site/permit-site-input"; +import { DecisionDto } from "./ceeb/decision/decision-input"; export interface CaseFileDto { caseIdentifier: UUID; @@ -18,4 +20,6 @@ export interface CaseFileDto { isReviewRequired: boolean; reviewComplete: FileReviewActionDto; note?: Note; + authorization?: PermitSiteDto; + decision?: DecisionDto; } diff --git a/backend/src/types/models/case-files/ceeb/decision/create-decision-input.ts b/backend/src/types/models/case-files/ceeb/decision/create-decision-input.ts index 1fc0bc61b..6501c77b2 100644 --- a/backend/src/types/models/case-files/ceeb/decision/create-decision-input.ts +++ b/backend/src/types/models/case-files/ceeb/decision/create-decision-input.ts @@ -1,6 +1,6 @@ import { BaseCaseFileInput } from "../../base-case-file-input"; -import { DecisionInput } from "./decision-input"; +import { DecisionDto } from "./decision-input"; export interface CreateDecisionInput extends BaseCaseFileInput { - decison: DecisionInput; + decison: DecisionDto; } diff --git a/backend/src/types/models/case-files/ceeb/decision/decision-input.ts b/backend/src/types/models/case-files/ceeb/decision/decision-input.ts index 8d9480201..2c01541e8 100644 --- a/backend/src/types/models/case-files/ceeb/decision/decision-input.ts +++ b/backend/src/types/models/case-files/ceeb/decision/decision-input.ts @@ -1,4 +1,4 @@ -export interface DecisionInput { +export interface DecisionDto { id?: string; schedule: string; sector: string; diff --git a/backend/src/types/models/case-files/ceeb/decision/update-decison-input.ts b/backend/src/types/models/case-files/ceeb/decision/update-decison-input.ts index f6eec2c08..99889b7e1 100644 --- a/backend/src/types/models/case-files/ceeb/decision/update-decison-input.ts +++ b/backend/src/types/models/case-files/ceeb/decision/update-decison-input.ts @@ -1,8 +1,8 @@ import { BaseCaseFileInput } from "../../base-case-file-input"; -import { DecisionInput } from "./decision-input"; +import { DecisionDto } from "./decision-input"; export interface UpdateDecisionInput extends BaseCaseFileInput { agencyCode: string; caseCode: string; - decison: DecisionInput; + decison: DecisionDto; } diff --git a/backend/src/types/models/case-files/ceeb/site/create-authorization-outcome-input.ts b/backend/src/types/models/case-files/ceeb/site/create-authorization-outcome-input.ts index e7c8e3932..c284f2924 100644 --- a/backend/src/types/models/case-files/ceeb/site/create-authorization-outcome-input.ts +++ b/backend/src/types/models/case-files/ceeb/site/create-authorization-outcome-input.ts @@ -1,6 +1,6 @@ import { BaseCaseFileInput } from "../../base-case-file-input"; -import { PermitSiteInput } from "./permit-site-input"; +import { PermitSiteDto } from "./permit-site-input"; export interface CreateAuthorizationOutcomeInput extends BaseCaseFileInput { - input: PermitSiteInput; + input: PermitSiteDto; } diff --git a/backend/src/types/models/case-files/ceeb/site/permit-site-input.ts b/backend/src/types/models/case-files/ceeb/site/permit-site-input.ts index a3d9d9c66..4a81764b7 100644 --- a/backend/src/types/models/case-files/ceeb/site/permit-site-input.ts +++ b/backend/src/types/models/case-files/ceeb/site/permit-site-input.ts @@ -1,4 +1,4 @@ -export interface PermitSiteInput { +export interface PermitSiteDto { id?: string; type: "permit" | "site"; value: string; diff --git a/backend/src/types/models/case-files/ceeb/site/update-authorization-outcome-input.ts b/backend/src/types/models/case-files/ceeb/site/update-authorization-outcome-input.ts index 18ea496fd..734f4a06c 100644 --- a/backend/src/types/models/case-files/ceeb/site/update-authorization-outcome-input.ts +++ b/backend/src/types/models/case-files/ceeb/site/update-authorization-outcome-input.ts @@ -1,6 +1,6 @@ import { BaseCaseFileInput } from "../../base-case-file-input"; -import { PermitSiteInput } from "./permit-site-input"; +import { PermitSiteDto } from "./permit-site-input"; export interface UpdateAuthorizationOutcomeInput extends BaseCaseFileInput { - input: PermitSiteInput; + input: PermitSiteDto; } diff --git a/backend/src/types/models/reports/complaints/complaint-report-data.ts b/backend/src/types/models/reports/complaints/complaint-report-data.ts index 23d370005..76f368e4f 100644 --- a/backend/src/types/models/reports/complaints/complaint-report-data.ts +++ b/backend/src/types/models/reports/complaints/complaint-report-data.ts @@ -9,6 +9,7 @@ export interface ComplaintReportData { generatedOn: string; updatedOn: Date | string; createdBy: string; + ownedBy: string; officerAssigned: string; status: string; incidentDateTime: Date | string; diff --git a/backend/src/v1/case_file/case_file.module.ts b/backend/src/v1/case_file/case_file.module.ts index 843f4961c..6e09f47e5 100644 --- a/backend/src/v1/case_file/case_file.module.ts +++ b/backend/src/v1/case_file/case_file.module.ts @@ -18,5 +18,6 @@ import { LinkedComplaintXref } from "../linked_complaint_xref/entities/linked_co ], controllers: [CaseFileController], providers: [CaseFileService], + exports: [CaseFileService], }) export class CaseFileModule {} diff --git a/backend/src/v1/case_file/case_file.service.spec.ts b/backend/src/v1/case_file/case_file.service.spec.ts index b489861c4..8b30052bc 100644 --- a/backend/src/v1/case_file/case_file.service.spec.ts +++ b/backend/src/v1/case_file/case_file.service.spec.ts @@ -64,6 +64,13 @@ import { TeamCode } from "../team_code/entities/team_code.entity"; import { CompMthdRecvCdAgcyCdXref } from "../comp_mthd_recv_cd_agcy_cd_xref/entities/comp_mthd_recv_cd_agcy_cd_xref"; import { CompMthdRecvCdAgcyCdXrefService } from "../comp_mthd_recv_cd_agcy_cd_xref/comp_mthd_recv_cd_agcy_cd_xref.service"; import { LinkedComplaintXref } from "../linked_complaint_xref/entities/linked_complaint_xref.entity"; +import { OfficerService } from "../officer/officer.service"; +import { PersonService } from "../person/person.service"; +import { OfficeService } from "../office/office.service"; +import { CssService } from "../../external_api/css/css.service"; +import { ConfigurationService } from "../configuration/configuration.service"; +import { Configuration } from "../configuration/entities/configuration.entity"; +import { Person } from "../person/entities/person.entity"; describe("Testing: Case File Service", () => { let service: CaseFileService; @@ -192,10 +199,23 @@ describe("Testing: Case File Service", () => { provide: getRepositoryToken(LinkedComplaintXref), useValue: {}, }, + { + provide: getRepositoryToken(Configuration), + useValue: {}, + }, + { + provide: getRepositoryToken(Person), + useValue: {}, + }, ComplaintUpdatesService, CaseFileService, ComplaintService, CodeTableService, + OfficerService, + OfficeService, + CssService, + ConfigurationService, + PersonService, PersonComplaintXrefService, AttractantHwcrXrefService, CompMthdRecvCdAgcyCdXrefService, diff --git a/backend/src/v1/case_file/case_file.service.ts b/backend/src/v1/case_file/case_file.service.ts index 892786d5e..a33c0c4d6 100644 --- a/backend/src/v1/case_file/case_file.service.ts +++ b/backend/src/v1/case_file/case_file.service.ts @@ -1,7 +1,7 @@ import { Inject, Injectable, Logger, Scope } from "@nestjs/common"; import { InjectMapper } from "@automapper/nestjs"; import { Mapper } from "@automapper/core"; -import { get, post } from "../../external_api/case_management"; +import { caseFileQueryFields, get, post } from "../../external_api/case_management"; import { CaseFileDto } from "src/types/models/case-files/case-file"; import { REQUEST } from "@nestjs/core"; import { AxiosResponse, AxiosError } from "axios"; @@ -32,130 +32,6 @@ export class CaseFileService { private readonly logger = new Logger(CaseFileService.name); private mapper: Mapper; - private caseFileQueryFields: string = ` - { - caseIdentifier - leadIdentifier - assessmentDetails { - actionNotRequired - actionJustificationCode - actionJustificationShortDescription - actionJustificationLongDescription - actionJustificationActiveIndicator - actions { - actionId - actor - date - actionCode - shortDescription - longDescription - activeIndicator - } - } - isReviewRequired - reviewComplete { - actor - date - actionCode - actionId - activeIndicator - } - preventionDetails { - actions { - actionId - actor - date - actionCode - shortDescription - longDescription - activeIndicator - } - } - note { - note - action { - actor - actionCode - date, - actionId, - activeIndicator - } - } - equipment { - id - typeCode - activeIndicator - address - xCoordinate - yCoordinate - createDate - actions { - actionId - actor - actionCode - date - } - wasAnimalCaptured - }, - subject { - id - species - sex - age - categoryLevel - conflictHistory - outcome - tags { - id - ear - identifier - - order - } - drugs { - id - - vial - drug - amountUsed - injectionMethod - reactions - - remainingUse - amountDiscarded - discardMethod - - order - } - actions { - actionId - actor - actionCode - date - } - order - } - decision { - id - schedule - sector - discharge - nonCompliance - rationale - inspectionNumber - leadAgency - assignedTo - actionTaken - actionTakenDate - } - authorization { - id - type - value - } - } - `; - constructor( @Inject(REQUEST) private request: Request, @InjectMapper() mapper, @@ -169,7 +45,7 @@ export class CaseFileService { find = async (complaint_id: string, token: string): Promise => { const { data, errors } = await get(token, { query: `{getCaseFileByLeadId (leadIdentifier: "${complaint_id}") - ${this.caseFileQueryFields} + ${caseFileQueryFields} }`, }); @@ -291,7 +167,7 @@ export class CaseFileService { const result = await post(token, { query: `mutation CreateAssessment($createAssessmentInput: CreateAssessmentInput!) { createAssessment(createAssessmentInput: $createAssessmentInput) - ${this.caseFileQueryFields} + ${caseFileQueryFields} }`, variables: model, }); @@ -310,7 +186,7 @@ export class CaseFileService { const result = await post(token, { query: `mutation CreateAssessment($createAssessmentInput: CreateAssessmentInput!) { createAssessment(createAssessmentInput: $createAssessmentInput) - ${this.caseFileQueryFields} + ${caseFileQueryFields} }`, variables: model, }); @@ -324,7 +200,7 @@ export class CaseFileService { const result = await post(token, { query: `mutation UpdateAssessment($updateAssessmentInput: UpdateAssessmentInput!) { updateAssessment(updateAssessmentInput: $updateAssessmentInput) - ${this.caseFileQueryFields} + ${caseFileQueryFields} }`, variables: model, }); @@ -336,7 +212,7 @@ export class CaseFileService { const result = await post(token, { query: `mutation CreateReview($reviewInput: ReviewInput!) { createReview(reviewInput: $reviewInput) - ${this.caseFileQueryFields} + ${caseFileQueryFields} }`, variables: model, }); @@ -359,7 +235,7 @@ export class CaseFileService { const result = await post(token, { query: `mutation UpdateReview($reviewInput: ReviewInput!) { updateReview(reviewInput: $reviewInput) - ${this.caseFileQueryFields} + ${caseFileQueryFields} }`, variables: model, }); @@ -388,7 +264,7 @@ export class CaseFileService { const result = await post(token, { query: `mutation CreatePrevention($createPreventionInput: CreatePreventionInput!) { createPrevention(createPreventionInput: $createPreventionInput) - ${this.caseFileQueryFields} + ${caseFileQueryFields} }`, variables: model, }); @@ -400,7 +276,7 @@ export class CaseFileService { const result = await post(token, { query: `mutation UpdatePrevention($updatePreventionInput: UpdatePreventionInput!) { updatePrevention(updatePreventionInput: $updatePreventionInput) - ${this.caseFileQueryFields} + ${caseFileQueryFields} }`, variables: model, }); @@ -427,7 +303,7 @@ export class CaseFileService { const mutationQuery = { query: `mutation CreateEquipment($createEquipmentInput: CreateEquipmentInput!) { createEquipment(createEquipmentInput: $createEquipmentInput) - ${this.caseFileQueryFields} + ${caseFileQueryFields} }`, variables: model, }; @@ -444,7 +320,7 @@ export class CaseFileService { const result = await post(token, { query: `mutation UpdateEquipment($updateEquipmentInput: UpdateEquipmentInput!) { updateEquipment(updateEquipmentInput: $updateEquipmentInput) - ${this.caseFileQueryFields} + ${caseFileQueryFields} }`, variables: model, }); diff --git a/backend/src/v1/complaint/complaint.module.ts b/backend/src/v1/complaint/complaint.module.ts index 14ca39afc..daa4fc6fc 100644 --- a/backend/src/v1/complaint/complaint.module.ts +++ b/backend/src/v1/complaint/complaint.module.ts @@ -33,6 +33,7 @@ import { CompMthdRecvCdAgcyCdXref } from "../comp_mthd_recv_cd_agcy_cd_xref/enti import { CompMthdRecvCdAgcyCdXrefService } from "../comp_mthd_recv_cd_agcy_cd_xref/comp_mthd_recv_cd_agcy_cd_xref.service"; import { CompMthdRecvCdAgcyCdXrefModule } from "../comp_mthd_recv_cd_agcy_cd_xref/comp_mthd_recv_cd_agcy_cd_xref.module"; import { LinkedComplaintXrefModule } from "../linked_complaint_xref/linked_complaint_xref.module"; +import { OfficerModule } from "../officer/officer.module"; @Module({ imports: [ @@ -67,6 +68,7 @@ import { LinkedComplaintXrefModule } from "../linked_complaint_xref/linked_compl StagingComplaintModule, CompMthdRecvCdAgcyCdXrefModule, LinkedComplaintXrefModule, + OfficerModule, ], controllers: [ComplaintController], providers: [ComplaintService, CompMthdRecvCdAgcyCdXrefService], diff --git a/backend/src/v1/complaint/complaint.service.spec.ts b/backend/src/v1/complaint/complaint.service.spec.ts index a49e67c54..3b8f00787 100644 --- a/backend/src/v1/complaint/complaint.service.spec.ts +++ b/backend/src/v1/complaint/complaint.service.spec.ts @@ -70,6 +70,13 @@ import { StagingComplaint } from "../staging_complaint/entities/staging_complain import { TeamCode } from "../team_code/entities/team_code.entity"; import { CompMthdRecvCdAgcyCdXrefService } from "../comp_mthd_recv_cd_agcy_cd_xref/comp_mthd_recv_cd_agcy_cd_xref.service"; import { CompMthdRecvCdAgcyCdXref } from "../comp_mthd_recv_cd_agcy_cd_xref/entities/comp_mthd_recv_cd_agcy_cd_xref"; +import { OfficerService } from "../officer/officer.service"; +import { PersonService } from "../person/person.service"; +import { OfficeService } from "../office/office.service"; +import { CssService } from "../../external_api/css/css.service"; +import { ConfigurationService } from "../configuration/configuration.service"; +import { Person } from "../person/entities/person.entity"; +import { Configuration } from "../configuration/entities/configuration.entity"; describe("Testing: Complaint Service", () => { let service: ComplaintService; @@ -93,9 +100,22 @@ describe("Testing: Complaint Service", () => { provide: getRepositoryToken(ActionTaken), useValue: {}, }, + { + provide: getRepositoryToken(Configuration), + useValue: {}, + }, + { + provide: getRepositoryToken(Person), + useValue: {}, + }, ComplaintUpdatesService, ComplaintService, PersonComplaintXrefService, + OfficerService, + OfficeService, + CssService, + ConfigurationService, + PersonService, AttractantHwcrXrefService, CodeTableService, CompMthdRecvCdAgcyCdXrefService, @@ -360,9 +380,22 @@ describe("Testing: Complaint Service", () => { provide: getRepositoryToken(ActionTaken), useValue: {}, }, + { + provide: getRepositoryToken(Configuration), + useValue: {}, + }, + { + provide: getRepositoryToken(Person), + useValue: {}, + }, ComplaintUpdatesService, ComplaintService, PersonComplaintXrefService, + OfficerService, + OfficeService, + CssService, + ConfigurationService, + PersonService, AttractantHwcrXrefService, CodeTableService, CompMthdRecvCdAgcyCdXrefService, diff --git a/backend/src/v1/complaint/complaint.service.ts b/backend/src/v1/complaint/complaint.service.ts index b8f15d4dd..b9b75797e 100644 --- a/backend/src/v1/complaint/complaint.service.ts +++ b/backend/src/v1/complaint/complaint.service.ts @@ -4,7 +4,7 @@ import { InjectRepository } from "@nestjs/typeorm"; import { Brackets, DataSource, QueryRunner, Repository, SelectQueryBuilder } from "typeorm"; import { InjectMapper } from "@automapper/nestjs"; import { Mapper } from "@automapper/core"; -import { get } from "../../external_api/case_management"; +import { caseFileQueryFields, get } from "../../external_api/case_management"; import { applyAllegationComplaintMap, @@ -66,6 +66,7 @@ import { WildlifeReportData } from "src/types/models/reports/complaints/wildlife import { AllegationReportData } from "src/types/models/reports/complaints/allegation-report-data"; import { RelatedDataDto } from "src/types/models/complaints/related-data"; import { CompMthdRecvCdAgcyCdXrefService } from "../comp_mthd_recv_cd_agcy_cd_xref/comp_mthd_recv_cd_agcy_cd_xref.service"; +import { OfficerService } from "../officer/officer.service"; type complaintAlias = HwcrComplaint | AllegationComplaint | GirComplaint; @Injectable({ scope: Scope.REQUEST }) @@ -91,13 +92,15 @@ export class ComplaintService { private _cosOrganizationUnitRepository: Repository; constructor( - @Inject(REQUEST) private request: Request, + @Inject(REQUEST) + private readonly request: Request, @InjectMapper() mapper, private readonly _codeTableService: CodeTableService, private readonly _compliantUpdatesService: ComplaintUpdatesService, private readonly _personService: PersonComplaintXrefService, private readonly _attractantService: AttractantHwcrXrefService, private readonly _compMthdRecvCdAgcyCdXrefService: CompMthdRecvCdAgcyCdXrefService, + private readonly _officerService: OfficerService, private dataSource: DataSource, ) { this.mapper = mapper; @@ -1512,7 +1515,7 @@ export class ComplaintService { return results; }; - getReportData = async (id: string, complaintType: COMPLAINT_TYPE, tz: string) => { + getReportData = async (id: string, complaintType: COMPLAINT_TYPE, tz: string, token: string) => { let data; mapWildlifeReport(this.mapper, tz); mapAllegationReport(this.mapper, tz); @@ -1575,6 +1578,42 @@ export class ComplaintService { } }; + const _getCaseData = async (id: string, token: string) => { + //-- Get the Outcome Data, this is done via a GQL call to prevent + //-- a circular dependency between the complaint and case_file modules + const { data, errors } = await get(token, { + query: `{getCaseFileByLeadId (leadIdentifier: "${id}") + ${caseFileQueryFields} + }`, + }); + if (errors) { + this.logger.error("GraphQL errors:", errors); + throw new Error("GraphQL errors occurred"); + } + + //-- Clean up the data to make it easier for formatting + let outcomeData = data; + //-- Add UA to unpermitted sites + if ( + outcomeData.getCaseFileByLeadId.authorization && + outcomeData.getCaseFileByLeadId.authorization.type !== "permit" + ) { + outcomeData.getCaseFileByLeadId.authorization.value = + "UA" + outcomeData.getCaseFileByLeadId.authorization.value; + } + + //-- Convert Officer Guids to Names + if (outcomeData.getCaseFileByLeadId.note) { + const { first_name, last_name } = ( + await this._officerService.findByAuthUserGuid(outcomeData.getCaseFileByLeadId.note.action.actor) + ).person_guid; + + outcomeData.getCaseFileByLeadId.note.action.actor = last_name + ", " + first_name; + } + + return outcomeData.getCaseFileByLeadId; + }; + try { if (complaintType) { builder = this._generateQueryBuilder(complaintType); @@ -1629,19 +1668,28 @@ export class ComplaintService { "AllegationComplaint", "AllegationReportData", ); - - //-- this is a bit of a hack to hide and show the privacy requested row - if (data.privacyRequested) { - data = { ...data, privacy: [{ value: data.privacyRequested }] }; - } - break; } } + //-- get case data + data.outcome = await _getCaseData(id, token); + //-- get any updates a complaint may have data.updates = await _getUpdates(id); + //-- this is a workaround to hide empty rows in the carbone templates + //-- It could possibly be removed if the CDOGS version of Carbone is updated + if (data.privacyRequested) { + data = { ...data, privacy: [{ value: data.privacyRequested }] }; + } + if (data.outcome.decision?.leadAgencyLongDescription) { + data = { ...data, agency: [{ value: data.outcome.decision.leadAgencyLongDescription }] }; + } + if (data.outcome.decision?.inspectionNumber) { + data = { ...data, inspection: [{ value: data.outcome.decision.inspectionNumber }] }; + } + //-- problems in the automapper mean dates need to be handled //-- seperatly const current = new Date(); @@ -1652,6 +1700,14 @@ export class ComplaintService { data.reportedOn = _applyTimezone(data.reportedOn, tz, "datetime"); data.updatedOn = _applyTimezone(data.updatedOn, tz, "datetime"); + if (data.outcome.note) { + data.outcome.note.action.date = _applyTimezone(data.outcome.note.action.date, tz, "date"); + } + + if (data.outcome.decision) { + data.outcome.decision.actionTakenDate = _applyTimezone(data.outcome.decision.actionTakenDate, tz, "date"); + } + //-- incidentDateTime may not be set, if there's no date //-- don't try and apply the incident date if (data.incidentDateTime) { diff --git a/backend/src/v1/document/document.controller.spec.ts b/backend/src/v1/document/document.controller.spec.ts index b907efb57..1b132450e 100644 --- a/backend/src/v1/document/document.controller.spec.ts +++ b/backend/src/v1/document/document.controller.spec.ts @@ -67,6 +67,11 @@ import { StagingComplaint } from "../staging_complaint/entities/staging_complain import { TeamCode } from "../team_code/entities/team_code.entity"; import { CompMthdRecvCdAgcyCdXref } from "../comp_mthd_recv_cd_agcy_cd_xref/entities/comp_mthd_recv_cd_agcy_cd_xref"; import { CompMthdRecvCdAgcyCdXrefService } from "../comp_mthd_recv_cd_agcy_cd_xref/comp_mthd_recv_cd_agcy_cd_xref.service"; +import { OfficerService } from "../officer/officer.service"; +import { PersonService } from "../person/person.service"; +import { OfficeService } from "../office/office.service"; +import { CssService } from "../../external_api/css/css.service"; +import { Person } from "../person/entities/person.entity"; describe("DocumentController", () => { let controller: DocumentController; @@ -191,10 +196,18 @@ describe("DocumentController", () => { provide: getRepositoryToken(CompMthdRecvCdAgcyCdXref), useFactory: MockCompMthdRecvCdAgcyCdXrefRepository, }, + { + provide: getRepositoryToken(Person), + useValue: {}, + }, ComplaintUpdatesService, ComplaintService, CodeTableService, PersonComplaintXrefService, + OfficerService, + OfficeService, + CssService, + PersonService, AttractantHwcrXrefService, CompMthdRecvCdAgcyCdXrefService, { diff --git a/backend/src/v1/document/document.controller.ts b/backend/src/v1/document/document.controller.ts index 2fab8532c..4311e3d23 100644 --- a/backend/src/v1/document/document.controller.ts +++ b/backend/src/v1/document/document.controller.ts @@ -29,7 +29,7 @@ export class DocumentController { ): Promise { try { const fileName = `Complaint-${id}-${type}-${format(new Date(), "yyyy-MM-dd")}.pdf`; - const response = await this.service.exportComplaint(id, type, fileName, tz); + const response = await this.service.exportComplaint(id, type, fileName, tz, token); if (!response || !response.data) { throw Error(`exception: unable to export document for complaint: ${id}`); diff --git a/backend/src/v1/document/document.service.spec.ts b/backend/src/v1/document/document.service.spec.ts index 359e45aa4..11ef41b49 100644 --- a/backend/src/v1/document/document.service.spec.ts +++ b/backend/src/v1/document/document.service.spec.ts @@ -66,6 +66,11 @@ import { StagingComplaint } from "../staging_complaint/entities/staging_complain import { TeamCode } from "../team_code/entities/team_code.entity"; import { CompMthdRecvCdAgcyCdXrefService } from "../comp_mthd_recv_cd_agcy_cd_xref/comp_mthd_recv_cd_agcy_cd_xref.service"; import { CompMthdRecvCdAgcyCdXref } from "../comp_mthd_recv_cd_agcy_cd_xref/entities/comp_mthd_recv_cd_agcy_cd_xref"; +import { OfficerService } from "../officer/officer.service"; +import { PersonService } from "../person/person.service"; +import { OfficeService } from "../office/office.service"; +import { CssService } from "../../external_api/css/css.service"; +import { Person } from "../person/entities/person.entity"; describe("DocumentService", () => { let service: DocumentService; @@ -190,10 +195,18 @@ describe("DocumentService", () => { provide: getRepositoryToken(CompMthdRecvCdAgcyCdXref), useFactory: MockCompMthdRecvCdAgcyCdXrefRepository, }, + { + provide: getRepositoryToken(Person), + useValue: {}, + }, ComplaintUpdatesService, ComplaintService, CodeTableService, PersonComplaintXrefService, + OfficerService, + OfficeService, + CssService, + PersonService, AttractantHwcrXrefService, CompMthdRecvCdAgcyCdXrefService, { diff --git a/backend/src/v1/document/document.service.ts b/backend/src/v1/document/document.service.ts index e3939d950..6a2f35b50 100644 --- a/backend/src/v1/document/document.service.ts +++ b/backend/src/v1/document/document.service.ts @@ -17,11 +17,11 @@ export class DocumentService { //-- using the cdogs api generate a new document from the specified //-- complaint-id and complaint type //-- - exportComplaint = async (id: string, type: COMPLAINT_TYPE, name: string, tz: string) => { + exportComplaint = async (id: string, type: COMPLAINT_TYPE, name: string, tz: string, token: string) => { try { //-- get the complaint from the system, but do not include anything other //-- than the base complaint. no maps, no attachments, no outcome data - const data = await this.ceds.getReportData(id, type, tz); + const data = await this.ceds.getReportData(id, type, tz, token); //-- return await this.cdogs.generate(name, data, type); diff --git a/backend/src/v1/officer/officer.module.ts b/backend/src/v1/officer/officer.module.ts index 0e2ce3d35..8b4561be9 100644 --- a/backend/src/v1/officer/officer.module.ts +++ b/backend/src/v1/officer/officer.module.ts @@ -18,5 +18,6 @@ import { CssModule } from "src/external_api/css/css.module"; ], controllers: [OfficerController], providers: [OfficerService, PersonService, OfficeService], + exports: [OfficerService], }) export class OfficerModule {} diff --git a/backend/templates/complaint/CDOGS-CEEB-COMPLAINT-TEMPLATE-v1.docx b/backend/templates/complaint/CDOGS-CEEB-COMPLAINT-TEMPLATE-v1.docx new file mode 100644 index 000000000..7be974984 Binary files /dev/null and b/backend/templates/complaint/CDOGS-CEEB-COMPLAINT-TEMPLATE-v1.docx differ diff --git a/backend/templates/complaint/CDOGS-ERS-COMPLAINT-TEMPLATE-v1.docx b/backend/templates/complaint/CDOGS-ERS-COMPLAINT-TEMPLATE-v1.docx index 70030ede8..6e08cbc30 100644 Binary files a/backend/templates/complaint/CDOGS-ERS-COMPLAINT-TEMPLATE-v1.docx and b/backend/templates/complaint/CDOGS-ERS-COMPLAINT-TEMPLATE-v1.docx differ diff --git a/backend/templates/complaint/CDOGS-HWCR-COMPLAINT-TEMPLATE-v1.docx b/backend/templates/complaint/CDOGS-HWCR-COMPLAINT-TEMPLATE-v1.docx index 7180de5de..f23ed6510 100644 Binary files a/backend/templates/complaint/CDOGS-HWCR-COMPLAINT-TEMPLATE-v1.docx and b/backend/templates/complaint/CDOGS-HWCR-COMPLAINT-TEMPLATE-v1.docx differ diff --git a/migrations/migrations/R__Create-Test-Data.sql b/migrations/migrations/R__Create-Test-Data.sql index 06f7dfd07..f1b4065d2 100644 --- a/migrations/migrations/R__Create-Test-Data.sql +++ b/migrations/migrations/R__Create-Test-Data.sql @@ -9795,6 +9795,32 @@ SELECT now() ON CONFLICT DO NOTHING; +------------------------ +-- New Template: CEEB +------------------------ +INSERT INTO + configuration ( + configuration_code, + configuration_value, + long_description, + active_ind, + create_user_id, + create_utc_timestamp, + update_user_id, + update_utc_timestamp + ) +VALUES + ( + 'CEEBTMPLAT', + '', + 'CDOGS Hash for CEEB Template', + true, + CURRENT_USER, + CURRENT_TIMESTAMP, + CURRENT_USER, + CURRENT_TIMESTAMP + ) ON CONFLICT DO NOTHING; + -------------------------- -- New Changes above this line diff --git a/migrations/migrations/R__reset-templates.sql b/migrations/migrations/R__reset-templates.sql index d0aa25ead..e70d32d46 100644 --- a/migrations/migrations/R__reset-templates.sql +++ b/migrations/migrations/R__reset-templates.sql @@ -11,4 +11,4 @@ UPDATE "configuration" SET configuration_value = '' WHERE - configuration_code IN ('ERSTMPLATE', 'HWCTMPLATE'); \ No newline at end of file + configuration_code IN ('ERSTMPLATE', 'HWCTMPLATE', 'CEEBTMPLATE'); \ No newline at end of file