Skip to content

Commit

Permalink
Merge pull request #308 from bcgov/ofmcc-4329-show-irreg-expense
Browse files Browse the repository at this point in the history
Ofmcc 4329 show irreg expense
  • Loading branch information
jenbeckett authored Jul 29, 2024
2 parents 1c0bc99 + 5f1da8c commit b6c80ea
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 15 deletions.
12 changes: 12 additions & 0 deletions backend/src/components/documents.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ async function getDocuments(req, res) {
}
}

//returns a base64 encoded version of a document to download or display on the portal
async function getDocumentFile(req, res) {
try {
const operation = `ofm_documents(${req.params.documentId})/ofm_file`
const response = await getOperation(operation)
return res.status(HttpStatus.OK).json(response?.value)
} catch (e) {
handleError(res, e)
}
}

async function createDocuments(req, res) {
try {
const { body, files } = req
Expand Down Expand Up @@ -61,4 +72,5 @@ module.exports = {
getDocuments,
createDocuments,
deleteDocument,
getDocumentFile,
}
17 changes: 16 additions & 1 deletion backend/src/routes/documents.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const passport = require('passport')
const router = express.Router()
const auth = require('../components/auth')
const isValidBackendToken = auth.isValidBackendToken()
const { getDocuments, createDocuments, deleteDocument } = require('../components/documents')
const { getDocuments, createDocuments, deleteDocument, getDocumentFile } = require('../components/documents')
const { param, query, validationResult } = require('express-validator')
const multer = require('multer')
const upload = multer()
Expand All @@ -20,6 +20,21 @@ router.get('/', passport.authenticate('jwt', { session: false }), isValidBackend
return getDocuments(req, res)
})

/**
* Get a base 64 encoded file by documentID
*/
router.get(
'/:documentId/file',
passport.authenticate('jwt', { session: false }),
isValidBackendToken,
[param('documentId', 'URL param: [documentId] is required').notEmpty().isUUID()],
validateRole(),
(req, res) => {
validationResult(req).throw()
return getDocumentFile(req, res)
},
)

/**
* Create new documents
*/
Expand Down
2 changes: 1 addition & 1 deletion backend/src/util/mapping/Mappings.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ const IrregularExpenseMappings = [
{ back: 'statuscode', front: 'statusCode' },
{ back: 'ofm_caption', front: 'referenceNumber' },
{ back: '[email protected]', front: 'statusName' },
{ back: 'ofm_assistance_requestid', front: 'assistanceRequestId' },
{ back: '_ofm_assistance_request_value', front: 'assistanceRequestId' },
{ back: 'ofm_start_date', front: 'startDate' },
{ back: 'ofm_end_date', front: 'endDate' },
{ back: 'ofm_expenseid', front: 'irregularExpenseId' },
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/services/documentService.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ export default {
}
},

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

async createDocuments(documents, entityId) {
const updatedDocuments = addEntityIdToDocument(documents, entityId)
const payload = mapDocumentFileObjectForBack(updatedDocuments)
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/utils/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,15 @@ export function convertArrayToString(item, separator = ', ') {
export function sanitizeWholeNumberInput(input) {
return input?.replace(/[^0-9]/g, '')
}

export function createPDFDownloadLink(file, fileName) {
const link = document.createElement('a')
link.href = `data:application/pdf;base64,${file}`
link.target = '_blank'
link.download = fileName

// Simulate a click on the element <a>
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
37 changes: 24 additions & 13 deletions frontend/src/views/applications/ApplicationsHistoryView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
<FacilityFilter v-if="!loading && !isEmpty(applicationItems)" :defaultShowInput="true" justify="end" @facility-filter-changed="facilityFilterChanged" />
</v-col>
</v-row>
<v-skeleton-loader :loading="loading" type="table-tbody">
<v-skeleton-loader id="table" :loading="loading" type="table-tbody">
<div v-if="isEmpty(applicationItems)">You have no applications on file</div>
<v-data-table v-else :headers="headers" :items="filteredApplicationItems" item-key="applicationId" :mobile="null" mobile-breakpoint="md" class="soft-outline" density="compact">
<template #item.status="{ item }">
Expand All @@ -82,6 +82,7 @@
<router-link v-if="item.applicationType !== APPLICATION_TYPES.IRREGULAR_EXPENSE" :to="getActionsRoute(item)">
{{ getApplicationAction(item) }}
</router-link>
<a v-else @click="getPDF(item)" href="#table">View Application</a>
</template>

<template #item.submittedDate="{ item }">
Expand Down Expand Up @@ -132,6 +133,9 @@ import IrregularExpenseService from '@/services/irregularExpenseService'
import FundingAgreementService from '@/services/fundingAgreementService'
import FacilityFilter from '@/components/facilities/FacilityFilter.vue'
import NewRequestDialog from '@/components/messages/NewRequestDialog.vue'
import DocumentService from '@/services/documentService'
import { createPDFDownloadLink } from '@/utils/common'
import {
APPLICATION_STATUS_CODES,
APPLICATION_ROUTES,
Expand Down Expand Up @@ -187,6 +191,7 @@ export default {
hasAValidFundingAgreement() {
return this.applications?.some((application) => application.fundingAgreement?.statusCode === FUNDING_AGREEMENT_STATUS_CODES.ACTIVE)
},
hasGoodStanding() {
return this.currentOrg?.goodStandingStatusCode === this.GOOD_STANDING_STATUS_CODES.GOOD
},
Expand Down Expand Up @@ -244,12 +249,11 @@ export default {
...mapActions(useOrgStore, ['getOrganizationInfo']),
isEmpty,
getApplicationAction(application) {
if (this.DRAFT_STATUS_CODES.includes(application?.statusCode) && application.applicationType !== APPLICATION_TYPES.IRREGULAR_EXPENSE) {
if (this.DRAFT_STATUS_CODES.includes(application?.statusCode)) {
return this.hasPermission(this.PERMISSIONS.APPLY_FOR_FUNDING) ? 'Continue Application' : 'View Application'
}
return 'View Application'
},
isApplicationCancellable(application) {
return this.DRAFT_STATUS_CODES.includes(application?.statusCode) && this.hasPermission(this.PERMISSIONS.APPLY_FOR_FUNDING) && application.applicationType !== APPLICATION_TYPES.IRREGULAR_EXPENSE
},
Expand Down Expand Up @@ -393,11 +397,24 @@ export default {
},
getActionsRoute(item) {
//JB TODO: link for irregular expense will download the application they previously uploaded
const routeName = item.applicationType === APPLICATION_TYPES.OFM ? APPLICATION_ROUTES.FACILITY_DETAILS : 'supp-allowances-form'
return { name: routeName, params: { applicationGuid: item?.applicationId } }
},
async getPDF(item) {
const doc = await DocumentService.getDocuments(item?.assistanceRequestId)
//TODO- post MVP - add a document Category / type to assistance request to find their application document
//this will return an array - we are assuming the user uploads their PDF first.
//we could add in to search for a file of type PDF - but we don't have requirements for this
const file = await DocumentService.getDocumentFileByID(doc[0]?.documentId)
try {
createPDFDownloadLink(file, doc[0]?.fileName)
} catch (error) {
this.setWarningAlert('PDF Generation is still in progress. Please wait a few minutes before you try again.')
}
},
sortApplicationItems(applicationItems) {
if (!applicationItems) return []
applicationItems.sort((a, b) => {
Expand All @@ -420,15 +437,7 @@ export default {
resp = await ApplicationService.getSupplementaryApplicationPDF(application.supplementaryApplicationId)
}
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)
createPDFDownloadLink(resp, application.referenceNumber)
} catch (error) {
this.setWarningAlert('PDF Generation is still in progress. Please wait a few minutes before you try again.')
}
Expand Down Expand Up @@ -456,6 +465,8 @@ export default {
submittedDate: null,
latestActivityDate: expense?.lastUpdatedTime,
statusCode: expense?.statusCode,
irregularExpenseId: expense?.irregularExpenseId,
assistanceRequestId: expense?.assistanceRequestId,
})
})
}
Expand Down

0 comments on commit b6c80ea

Please sign in to comment.