Skip to content

Commit

Permalink
Merge pull request #404 from bcgov/ofmcc-6328-funding-env-moves
Browse files Browse the repository at this point in the history
OFMCC-6328 - Funding envelope change request tables
  • Loading branch information
vietle-cgi authored Nov 1, 2024
2 parents e9fa611 + f38b419 commit f4c827b
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 9 deletions.
20 changes: 17 additions & 3 deletions backend/src/components/fundingAgreements.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
const { getOperation, patchOperationWithObjectId, getOperationWithObjectId, handleError } = require('./utils')
const { MappableObjectForFront, MappableObjectForBack } = require('../util/mapping/MappableObject')
const { buildDateFilterQuery, buildFilterQuery } = require('../util/common')
const { FundingAgreementMappings } = require('../util/mapping/Mappings')
const { FundingAgreementMappings, FundingReallocationRequestMappings } = require('../util/mapping/Mappings')
const HttpStatus = require('http-status-codes')
const log = require('./logger')
const { isEmpty } = require('lodash')
Expand Down Expand Up @@ -86,10 +86,24 @@ async function updateFundingAgreement(req, res) {
}
}

async function getFundingReallocationRequests(req, res) {
try {
const fundingReallocationRequests = []
const operation = `ofm_funding_envelope_changes?$select=ofm_funding_envelope_changeid,_ofm_funding_value,ofm_funding_envelope_from,ofm_funding_envelope_to,ofm_amount_base,createdon,statuscode
&$filter=(_ofm_funding_value eq ${req?.params?.fundingAgreementId})&pageSize=500`
const response = await getOperation(operation)
response?.value?.forEach((reallocationRequest) => fundingReallocationRequests.push(new MappableObjectForFront(reallocationRequest, FundingReallocationRequestMappings).toJSON()))
return res.status(HttpStatus.OK).json(fundingReallocationRequests)
} catch (e) {
handleError(res, e)
}
}

module.exports = {
getFundingAgreements,
updateFundingAgreement,
getFundingAgreementById,
getRawFundingAgreementById,
getFundingReallocationRequests,
getFundingPDFById,
getRawFundingAgreementById,
updateFundingAgreement,
}
18 changes: 17 additions & 1 deletion backend/src/routes/fundingAgreements.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 { getFundingAgreements, updateFundingAgreement, getFundingAgreementById, getFundingPDFById } = require('../components/fundingAgreements')
const { getFundingAgreements, updateFundingAgreement, getFundingAgreementById, getFundingPDFById, getFundingReallocationRequests } = require('../components/fundingAgreements')
const { param, query, validationResult, oneOf } = require('express-validator')
const validateExpenseAuthority = require('../middlewares/validateExpenseAuthority.js')
const validateFacility = require('../middlewares/validateFacility.js')
Expand Down Expand Up @@ -76,3 +76,19 @@ router.patch(
return updateFundingAgreement(req, res)
},
)

/**
* Get the list of Funding Reallocation Requests
*/
router.get(
'/:fundingAgreementId/funding-reallocation-requests',
passport.authenticate('jwt', { session: false }),
isValidBackendToken,
// TODO (vietle-cgi) - update permission once we receive confirmation for this requirement
validatePermission(PERMISSIONS.VIEW_FUNDING_AGREEMENT),
[param('fundingAgreementId', 'URL param: [fundingAgreementId] is required').notEmpty().isUUID()],
(req, res) => {
validationResult(req).throw()
return getFundingReallocationRequests(req, res)
},
)
14 changes: 14 additions & 0 deletions backend/src/util/mapping/Mappings.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,19 @@ const FundingAgreementMappings = [
{ back: 'ofm_envelope_facility', front: 'envelopeFacility' },
]

const FundingReallocationRequestMappings = [
{ back: 'ofm_funding_envelope_changeid', front: 'fundingEnvelopeId' },
{ back: '_ofm_funding_value', front: 'fundingId' },
{ back: 'ofm_funding_envelope_from', front: 'envelopeCodeFrom' },
{ back: 'ofm_funding_envelope_from@OData.Community.Display.V1.FormattedValue', front: 'envelopeNameFrom' },
{ back: 'ofm_funding_envelope_to', front: 'envelopeCodeTo' },
{ back: 'ofm_funding_envelope_to@OData.Community.Display.V1.FormattedValue', front: 'envelopeNameTo' },
{ back: 'ofm_amount_base', front: 'amount' },
{ back: 'createdon', front: 'date' },
{ back: 'statuscode', front: 'statusCode' },
{ back: '[email protected]', front: 'statusName' },
]

const PaymentMappings = [
{ back: 'ofm_paymentid', front: 'paymentId' },
{ back: 'ofm_name', front: 'paymentNumber' },
Expand Down Expand Up @@ -493,6 +506,7 @@ module.exports = {
FacilityIntakeMappings,
FacilityMappings,
FundingAgreementMappings,
FundingReallocationRequestMappings,
LicenceMappings,
LicenceDetailsMappings,
NotificationMappings,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/funding/BaseFundingCard.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<v-card elevation="2" class="ma-2">
<v-card-title class="card-title"><strong>Base Funding Paid</strong></v-card-title>
<v-card-title class="card-title"><strong>Base Funding</strong></v-card-title>
<v-skeleton-loader :loading="loading" type="table-tbody" class="pa-6">
<v-container fluid class="pa-0">
<div>The base funding shown is only from the current fiscal year and does not include changes from funding re-allocation requests.</div>
Expand Down
21 changes: 18 additions & 3 deletions frontend/src/components/funding/FundingAllocationTab.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
<template>
<v-container fluid class="pa-0">
<div class="ma-2">View or submit a change for your centre's current monthly funding allocations. Funds can be re-allocated based on the rules below.</div>
<v-row v-if="hasPermission(PERMISSIONS.SUBMIT_CHANGE_REQUEST)" no-gutters class="ma-2 justify-end">
<!-- TODO (vietle-cgi) - update permission once we receive confirmation for this requirement -->
<v-row v-if="hasPermission(PERMISSIONS.SUBMIT_CHANGE_REQUEST)" no-gutters class="mx-2 my-6 my-sm-2 justify-end">
<AppButton :loading="loading" @click="toggleAssistanceRequestDialog()">Request to Re-allocate Funds</AppButton>
</v-row>
<h2 class="ma-2">Funding Re-Allocation Rules</h2>
<AppAlertBanner type="info" class="ma-2 mb-4">Note: Total funds re-allocated cannot be more than the base funding for each envelope.</AppAlertBanner>
<FundingAllocationInfoTable class="pa-2" />
<FundingSearchCard :loading="loading" :select-single-facility="true" :show-date-filter="false" :show-reset-button="false" class="my-10" @search="loadFundingDetails" />
<BaseFundingCard :loading="loading" :funding-details="fundingDetails" />
<FundingReallocationRequestsTable :loading="loading" :funding-reallocation-requests="fundingReallocationRequests" class="mt-8" />
<NewRequestDialog
class="pa-0"
:show="showAssistanceRequestDialog"
Expand All @@ -23,6 +25,7 @@ import { mapState } from 'pinia'
import BaseFundingCard from '@/components/funding/BaseFundingCard.vue'
import FundingAllocationInfoTable from '@/components/funding/FundingAllocationInfoTable.vue'
import FundingReallocationRequestsTable from '@/components/funding/FundingReallocationRequestsTable.vue'
import FundingSearchCard from '@/components/funding/FundingSearchCard.vue'
import NewRequestDialog from '@/components/messages/NewRequestDialog.vue'
import AppAlertBanner from '@/components/ui/AppAlertBanner.vue'
Expand All @@ -35,14 +38,15 @@ import { FUNDING_AGREEMENT_STATUS_CODES, REQUEST_CATEGORY_NAMES } from '@/utils/
export default {
name: 'FundingAllocationTab',
components: { AppAlertBanner, AppButton, BaseFundingCard, FundingAllocationInfoTable, FundingSearchCard, NewRequestDialog },
components: { AppAlertBanner, AppButton, BaseFundingCard, FundingAllocationInfoTable, FundingReallocationRequestsTable, FundingSearchCard, NewRequestDialog },
mixins: [alertMixin, permissionsMixin],
data() {
return {
loading: false,
showAssistanceRequestDialog: false,
selectedFacility: null,
fundingDetails: {},
fundingReallocationRequests: [],
}
},
Expand All @@ -60,13 +64,24 @@ export default {
try {
this.loading = true
this.fundingDetails = await FundingAgreementService.getFundingEnvelopesByFacilityIdAndStatus(this.selectedFacility?.facilityId, FUNDING_AGREEMENT_STATUS_CODES.ACTIVE)
this.fundingReallocationRequests = await FundingAgreementService.getFundingReallocationRequestsByFundingAgreementId(this.fundingDetails?.fundingId)
this.sortFundingReallocationRequests()
} catch (error) {
this.setFailureAlert('Failed to load funding details', error)
this.setFailureAlert('Failed to load funding re-allocation requests', error)
} finally {
this.loading = false
}
},
// OFMCC-6328 - Sort by status first (In Progress > Approved > Ineligible > Cancelled), and then sort by Date (newest first)
sortFundingReallocationRequests() {
this.fundingReallocationRequests?.sort((a, b) => {
const dateA = new Date(a.date)
const dateB = new Date(b.date)
return a.statusCode > b.statusCode || dateB - dateA
})
},
toggleAssistanceRequestDialog() {
this.showAssistanceRequestDialog = !this.showAssistanceRequestDialog
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<template>
<v-container fluid class="px-2">
<h3>Funding Re-allocation Requests</h3>
<div class="pt-2 pb-4">The funding re-allocation requests shown include all fiscal years of the selected facility.</div>
<v-skeleton-loader :loading="loading" type="table-tbody">
<v-data-table
id="funding-requests-table"
:headers="fundingRequestsHeaders"
:items="fundingReallocationRequests"
item-key="fundingEnvelopeId"
density="compact"
:mobile="null"
mobile-breakpoint="md"
class="soft-outline">
<template #no-data>The selected facility has not submitted a funding re-allocation request.</template>
<template #[`item.date`]="{ item }">
{{ format.formatDate(item?.date) }}
</template>
<template #[`item.amount`]="{ item }">$ {{ format.formatDecimalNumber(item?.amount) }}</template>
<template #[`item.statusCode`]="{ item }">
<div class="min-width-column">
<span :class="getStatusClass(item?.statusCode)">{{ item?.statusName }}</span>
</div>
</template>
</v-data-table>
</v-skeleton-loader>
</v-container>
</template>

<script>
import { FUNDING_REALLOCATION_REQUEST_STATUS_CODES } from '@/utils/constants'
import format from '@/utils/format'

export default {
name: 'FundingReallocationRequestsTable',
props: {
loading: {
type: Boolean,
default: true,
},
fundingReallocationRequests: {
type: Array,
default: () => [],
},
},
data() {
return {
fundingRequestsHeaders: [
{ title: 'Date', key: 'date' },
{ title: 'From', key: 'envelopeNameFrom' },
{ title: 'To', key: 'envelopeNameTo' },
{ title: 'Amount', key: 'amount' },
{ title: 'Status', key: 'statusCode' },
],
}
},
created() {
this.format = format
},
methods: {
getStatusClass(statusCode) {
switch (statusCode) {
case FUNDING_REALLOCATION_REQUEST_STATUS_CODES.IN_PROGRESS:
return 'status-blue'
case FUNDING_REALLOCATION_REQUEST_STATUS_CODES.APPROVED:
return 'status-green'
case FUNDING_REALLOCATION_REQUEST_STATUS_CODES.CANCELLED:
return 'status-gray'
case FUNDING_REALLOCATION_REQUEST_STATUS_CODES.INELIGIBLE:
return 'status-red'
default:
return ''
}
},
},
}
</script>
<style scoped>
.min-width-column {
min-width: 105px;
}
</style>
9 changes: 8 additions & 1 deletion frontend/src/components/funding/FundingSearchCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
:rules="rules.required"
density="compact"
variant="outlined"
return-object />
return-object
class="wrapped-select" />
<v-select
v-else
v-model="selectedFacilities"
Expand Down Expand Up @@ -261,3 +262,9 @@ export default {
},
}
</script>
<style scoped>
:deep(.wrapped-select .v-select__selection-text) {
white-space: normal;
overflow-wrap: break-word;
}
</style>
11 changes: 11 additions & 0 deletions frontend/src/services/fundingAgreementService.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,15 @@ export default {
throw error
}
},

async getFundingReallocationRequestsByFundingAgreementId(fundingAgreementId) {
try {
if (!fundingAgreementId) return
const response = await ApiService.apiAxios.get(`${ApiRoutes.FUNDING_AGREEMENTS}/${fundingAgreementId}/funding-reallocation-requests`)
return response?.data
} catch (error) {
console.log(`Failed to get the funding reallocation requests by funding agreement id - ${error}`)
throw error
}
},
}
7 changes: 7 additions & 0 deletions frontend/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ export const FUNDING_AGREEMENT_STATUS_CODES = Object.freeze({
CANCELLED: 10,
})

export const FUNDING_REALLOCATION_REQUEST_STATUS_CODES = Object.freeze({
IN_PROGRESS: 1,
APPROVED: 2,
INELIGIBLE: 3,
CANCELLED: 4,
})

export const PAYMENT_STATUS_CODES = Object.freeze({
PENDING_PAYMENT: 1,
PAID: 2, // INACTIVE state
Expand Down

0 comments on commit f4c827b

Please sign in to comment.