Skip to content

Commit

Permalink
Merge pull request #250 from bcgov/ofmcc-3498-supp-app-timing-issue
Browse files Browse the repository at this point in the history
OFMCC-2351 - OFM core application View & Download PDF
  • Loading branch information
jenbeckett authored Jun 20, 2024
2 parents a2b7d5c + 02a3ab8 commit 2aefd9d
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 12 deletions.
12 changes: 12 additions & 0 deletions backend/src/components/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ async function getApplication(req, res) {
}
}

async function getApplicationPDF(req, res) {
try {
const operation = `ofm_applications(${req.params.applicationId})/ofm_application_pdf`
const response = await getOperation(operation)
return res.status(HttpStatus.OK).json(response?.value)
} catch (e) {
log.error(e)
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json(e.data ? e.data : e?.status)
}
}

async function updateApplication(req, res) {
try {
const payload = new MappableObjectForBack(req.body, ApplicationMappings).toJSON()
Expand Down Expand Up @@ -228,4 +239,5 @@ module.exports = {
createEmployeeCertificate,
updateEmployeeCertificate,
deleteEmployeeCertificate,
getApplicationPDF,
}
16 changes: 16 additions & 0 deletions backend/src/routes/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const {
createEmployeeCertificate,
updateEmployeeCertificate,
deleteEmployeeCertificate,
getApplicationPDF,
} = require('../components/applications')
const { param, validationResult, checkSchema } = require('express-validator')
const validatePermission = require('../middlewares/validatePermission.js')
Expand Down Expand Up @@ -95,6 +96,21 @@ router.get(
},
)

/**
* Get Funding Agreement PDF by ID
*/
router.get(
'/:applicationId/pdf',
passport.authenticate('jwt', { session: false }),
isValidBackendToken,
validatePermission(PERMISSIONS.VIEW_APPLICATIONS),
[param('applicationId', 'URL param: [applicationId] is required').not().isEmpty()],
(req, res) => {
validationResult(req).throw()
return getApplicationPDF(req, res)
},
)

/**
* Update an existing Application using applicationId
*/
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/components/applications/CancelApplicationDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
import AppButton from '@/components/ui/AppButton.vue'
import AppDialog from '@/components/ui/AppDialog.vue'
import alertMixin from '@/mixins/alertMixin'
import { APPLICATION_STATUS_CODES, SUPPLEMENTARY_APPLICATION_STATUS_CODES, CRM_STATE_CODES } from '@/utils/constants'
import { APPLICATION_STATUS_CODES, SUPPLEMENTARY_APPLICATION_STATUS_CODES, CRM_STATE_CODES, APPLICATION_TYPES } from '@/utils/constants'
import ApplicationService from '@/services/applicationService'
const APPLICATION_TYPES = {
const APPLICATION_LABELS = {
APPLICATION: 'Application',
SUPP_APPLICATION: 'Supplementary Application',
}
Expand Down Expand Up @@ -55,7 +55,7 @@ export default {
},
computed: {
sourceApplicationType() {
return this.applicationType === 'OFM' ? APPLICATION_TYPES.APPLICATION : APPLICATION_TYPES.SUPP_APPLICATION
return this.applicationType === APPLICATION_TYPES.OFM ? APPLICATION_LABELS.APPLICATION : APPLICATION_LABELS.SUPP_APPLICATION
},
},
watch: {
Expand All @@ -73,10 +73,10 @@ export default {
try {
this.isLoading = true
const payload = {
statusCode: this.sourceApplicationType === APPLICATION_TYPES.APPLICATION ? APPLICATION_STATUS_CODES.CANCELLED_BY_SP : SUPPLEMENTARY_APPLICATION_STATUS_CODES.CANCELLED,
statusCode: this.sourceApplicationType === APPLICATION_LABELS.APPLICATION ? APPLICATION_STATUS_CODES.CANCELLED_BY_SP : SUPPLEMENTARY_APPLICATION_STATUS_CODES.CANCELLED,
stateCode: CRM_STATE_CODES.INACTIVE,
}
if (this.sourceApplicationType === APPLICATION_TYPES.APPLICATION) {
if (this.sourceApplicationType === APPLICATION_LABELS.APPLICATION) {
await ApplicationService.updateApplication(this.applicationId, payload)
} else {
await ApplicationService.updateSupplementaryApplication(this.applicationId, payload)
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/services/applicationService.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ export default {
}
},

async getApplicationPDF(applicationId) {
try {
if (!applicationId) return
const response = await ApiService.apiAxios.get(`${ApiRoutes.APPLICATIONS}/${applicationId}/pdf`)
return response?.data
} catch (error) {
console.log(`Failed to get the application PDF by application id - ${error}`)
throw error
}
},

isApplicationUpdated(updatedApplication) {
const applicationsStore = useApplicationsStore()
const currentApplication = applicationsStore?.currentApplication
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,7 @@ export const NOT_IN_GOOD_STANDING_WARNING_MESSAGE =
'A BC Registries check has returned as "not in good standing" for your organization. Good standing is a requirement to receive OFM funding. Contact BC Registries immediately to resolve.'

export const BLANK_FIELD = '- - - -'

export const APPLICATION_TYPES = Object.freeze({
OFM: 'OFM',
})
43 changes: 37 additions & 6 deletions frontend/src/views/applications/ApplicationsHistoryView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
</template>

<template #item.actionButtons="{ item }">
<v-btn v-if="isApplicationDownloadable(item)" variant="text" @click="false">
<v-btn v-if="isApplicationDownloadable(item)" variant="text" @click="downloadPDF(item)">
<v-icon icon="fa:fa-regular fa-file-pdf"></v-icon>
</v-btn>
<v-btn v-if="isApplicationCancellable(item)" variant="text" @click="toggleCancelDialog(item)">
Expand All @@ -114,7 +114,14 @@ import CancelApplicationDialog from '@/components/applications/CancelApplication
import ApplicationService from '@/services/applicationService'
import FundingAgreementService from '@/services/fundingAgreementService'
import FacilityFilter from '@/components/facilities/FacilityFilter.vue'
import { APPLICATION_STATUS_CODES, APPLICATION_ROUTES, GOOD_STANDING_STATUS_CODES, SUPPLEMENTARY_APPLICATION_STATUS_CODES, NOT_IN_GOOD_STANDING_WARNING_MESSAGE } from '@/utils/constants'
import {
APPLICATION_STATUS_CODES,
APPLICATION_ROUTES,
GOOD_STANDING_STATUS_CODES,
SUPPLEMENTARY_APPLICATION_STATUS_CODES,
NOT_IN_GOOD_STANDING_WARNING_MESSAGE,
APPLICATION_TYPES,
} from '@/utils/constants'
import { mapState, mapActions } from 'pinia'
import { useAuthStore } from '@/stores/auth'
import { useOrgStore } from '@/stores/org'
Expand Down Expand Up @@ -220,7 +227,7 @@ export default {
},
toggleCancelDialog(item) {
this.cancelledApplicationId = item?.applicationType === 'OFM' ? item?.applicationId : item?.supplementaryApplicationId
this.cancelledApplicationId = item?.applicationType === APPLICATION_TYPES.OFM ? item?.applicationId : item?.supplementaryApplicationId
this.showCancelDialog = !this.showCancelDialog
if (item) {
this.applicationTypeToCancel = item.applicationType
Expand All @@ -229,7 +236,7 @@ export default {
cancelApplication() {
let index = undefined
const key = this.applicationTypeToCancel === 'OFM' ? 'applicationId' : 'supplementaryApplicationId'
const key = this.applicationTypeToCancel === APPLICATION_TYPES.OFM ? 'applicationId' : 'supplementaryApplicationId'
index = this.applicationItems?.findIndex((item) => item[key] === this.cancelledApplicationId)
if (index > -1) {
this.applicationItems.splice(index, 1)
Expand Down Expand Up @@ -275,7 +282,7 @@ export default {
}, {})
return {
...item,
applicationType: 'OFM',
applicationType: APPLICATION_TYPES.OFM,
statusCode: application.statusCode,
}
})
Expand Down Expand Up @@ -343,7 +350,7 @@ export default {
},
getActionsRoute(item) {
const routeName = item.applicationType === 'OFM' ? APPLICATION_ROUTES.FACILITY_DETAILS : 'supp-allowances-form'
const routeName = item.applicationType === APPLICATION_TYPES.OFM ? APPLICATION_ROUTES.FACILITY_DETAILS : 'supp-allowances-form'
return { name: routeName, params: { applicationGuid: item?.applicationId } }
},
Expand All @@ -360,6 +367,30 @@ export default {
})
return applicationItems
},
//TODO - Add Supp App PDF function will look very similar, but it will hit a seperate endpoint
//the supp app PDF's do not generate yet in Dynamics, so holding off on including that code
async downloadPDF(application) {
if (application.applicationType === APPLICATION_TYPES.OFM) {
try {
const resp = await ApplicationService.getApplicationPDF(application.applicationId)
const link = document.createElement('a')
link.href = `data:application/pdf;base64,${resp}`
link.target = '_blank'
link.download = application.referenceNumber
// Simulate a click on the element <a>
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
} catch (error) {
this.setFailureAlert('Failed to download OFM PDF', error)
}
} else {
//it's a supp app
this.setSuccessAlert(`COMING SOON! A supplementary PDF will be downloaded here.`)
}
},
},
}
</script>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/funding/FundingView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,12 @@ export default {
try {
this.loading = true
this.fundingAgreement = await FundingAgreementService.getFundingAgreementById(this.$route.params.fundingGuid)
await this.getLicences()
const resp = await FundingAgreementService.getFundingPDFById(this.$route.params.fundingGuid)
this.pdfFile = {
data: atob(resp),
}
this.pdfDownloadLink = `data:application/pdf;base64,${resp}`
await this.getLicences()
} finally {
this.loading = false
}
Expand Down

0 comments on commit 2aefd9d

Please sign in to comment.