diff --git a/src/api/repositories/assessment/assessment-cslft-repository-v2.ts b/src/api/repositories/assessment/assessment-cslft-repository-v2.ts index 671115ed..b91ab1c3 100644 --- a/src/api/repositories/assessment/assessment-cslft-repository-v2.ts +++ b/src/api/repositories/assessment/assessment-cslft-repository-v2.ts @@ -138,6 +138,9 @@ export class AssessmentCslftRepositoryV2 { await this.load(parseInt(`${fundingRequestId}`)); let assess = await this.calculateBase(); + + const existingOA = await this.db("sfa.assessment").where({ id: assessmentId }).select("over_award").first(); + if (existingOA) assess.over_award = existingOA.over_award; assess.id = parseInt(`${assessmentId}`); await this.calculateCosts(assess); @@ -145,7 +148,6 @@ export class AssessmentCslftRepositoryV2 { await this.calculateParental(assess); let full = await this.postLoad(assess, this.application.id); - assess.csl_assessed_need = full.csl_assessed_need; await this.calculateAward(assess); @@ -471,13 +473,18 @@ export class AssessmentCslftRepositoryV2 { "disbursed_amount" ); + const studentOverawards = await this.db("sfa.overaward").where({ student_id: this.student.id }); + const assessmentOverawards = studentOverawards.filter((o) => input.id == o.assessment_id); + + input.net_overaward = sumBy(studentOverawards, "amount"); + input.has_overaward_recorded = assessmentOverawards.find((o) => o.amount < 0) != null; + input.has_overaward_applied = assessmentOverawards.find((o) => o.amount > 0) != null; //over_award can only be as big as the calculated = clear partial + console.log("DOING MATH", input.over_award, input.assessed_amount); + input.net_amount = - input.assessed_amount /* - - (input.over_award ?? 0) */ - - input.previous_cert - - input.previous_disbursement /* - + input.assessed_amount /* - (input.over_award ?? 0) */ - input.previous_cert - input.previous_disbursement /* - (input.return_uncashable_cert ?? 0) */; input.net_amount = Math.round(input.net_amount * 100) / 100; @@ -538,7 +545,10 @@ export class AssessmentCslftRepositoryV2 { ); const calculated_award: number = Math.max(0, Math.round(calculated_award_min)); + console.log("DOING MATH 2", assess.over_award); + if (assess.csl_full_amt_flag == 0) { + console.log("M1"); assess.assessed_amount = Math.max( Math.min(calculated_award, assess.csl_request_amount ?? 0) - (assess.over_award ?? 0) - @@ -546,6 +556,7 @@ export class AssessmentCslftRepositoryV2 { 0 ); } else { + console.log("M2"); assess.assessed_amount = Math.max((calculated_award ?? 0) - (assess.over_award ?? 0), 0) - (assess.return_uncashable_cert ?? 0); } @@ -956,7 +967,7 @@ export class AssessmentCslftRepositoryV2 { (this.cslLookup.low_income_student_contrib_amount ?? 0) / e_month + ((family_income - income_threshold) / e_month) * ((this.cslLookup.student_contrib_percent ?? 0) / 100); - const weekly_calc = weekly_student_contrib * Math.min(assess.study_weeks ?? 0, max_weeks) ?? 0; + const weekly_calc = weekly_student_contrib * Math.min(assess.study_weeks ?? 0, max_weeks); assess.student_expected_contribution = Math.min(weekly_calc, this.cslLookup.student_contrib_max_amount ?? 0); assess.student_expected_contribution = Math.max( @@ -1041,14 +1052,14 @@ export class AssessmentCslftRepositoryV2 { let ftGrant = this.otherFunds.find((f) => f.request_type_id == 35); let ftDepGrant = this.otherFunds.find((f) => f.request_type_id == 32); let disGrant = this.otherFunds.find((f) => f.request_type_id == 29); - let disSEGrant = this.otherFunds.find((f) => f.request_type_id == 30); + //let disSEGrant = this.otherFunds.find((f) => f.request_type_id == 30); let topup = this.otherFunds.find((f) => f.request_type_id == 28); let totalGrants = (ftGrant?.disbursed_amount ?? 0) + (ftDepGrant?.disbursed_amount ?? 0) + (disGrant?.disbursed_amount ?? 0) + - (disSEGrant?.disbursed_amount ?? 0) + + //(disSEGrant?.disbursed_amount ?? 0) + (topup?.disbursed_amount ?? 0); assess.total_grant_awarded = totalGrants; @@ -1060,7 +1071,15 @@ export class AssessmentCslftRepositoryV2 { const calculated_award_min = Math.min(sixty - (assess.total_grant_awarded ?? 0), max_allowable ?? 0); const calculated_award: number = Math.max(0, Math.round(calculated_award_min)); - assess.over_award = this.student.pre_over_award_amount ?? 0; + /* const totalOveraward = await this.db("sfa.overaward").where({ + student_id: this.application.student_id, + }).sum("amount as total").first(); + + console.log("Total Overaward", totalOveraward?.total); */ + + //assess.over_award = assess.over_award ?? 0; // totalOveraward?.total ?? 0; + + console.log("Setting Overaward", assess.over_award); // Calculate the totaln_disbursments_required if (assess.csl_full_amt_flag == 0) { @@ -1461,4 +1480,8 @@ interface CSLFTAssessmentFull extends CSLFTAssessmentBase { student_other_resources: number; student_contrib_exempt_reason?: string; spouse_contrib_exempt_reason?: string; + + net_overaward: number; + has_overaward_recorded: boolean; + has_overaward_applied: boolean; } diff --git a/src/api/routes/admin/csg-threshold-router.ts b/src/api/routes/admin/csg-threshold-router.ts index 70cbaed3..1d1b2987 100644 --- a/src/api/routes/admin/csg-threshold-router.ts +++ b/src/api/routes/admin/csg-threshold-router.ts @@ -46,19 +46,23 @@ csgThresholdRouter.delete( async (req: Request, res: Response) => { const { assessment_id, funding_request_id } = req.params; - let disbursements = await db("sfa.disbursement").where({ assessment_id }); + try { + let disbursements = await db("sfa.disbursement").where({ assessment_id }); - if (disbursements) { - let eCertDisbursements = disbursements.filter((d) => d.csl_cert_seq_number); + if (disbursements) { + let eCertDisbursements = disbursements.filter((d) => d.csl_cert_seq_number); - if (eCertDisbursements.length) - return res.status(400).json({ errors: ["Cannot delete an assessment with eCert disbursements"] }); + if (eCertDisbursements.length) + return res.status(400).json({ errors: ["Cannot delete an assessment with eCert disbursements"] }); - await db("sfa.disbursement").where({ assessment_id }).delete(); - } + await db("sfa.disbursement").where({ assessment_id }).delete(); + } - await db("sfa.assessment").where({ id: assessment_id }).delete(); - return res.status(200).json({ data: "Assessment Deleted" }); + await db("sfa.assessment").where({ id: assessment_id }).delete(); + return res.status(200).json({ data: "Assessment Deleted" }); + } catch (e) { + res.status(400).json({ error: "Error deleting assessment - most likely due to applied overawards" }); + } } ); @@ -73,7 +77,6 @@ csgThresholdRouter.put( assessed_date, csl_over_reason_id, csl_non_reason_id, - over_award, return_uncashable_cert, student_contribution_override, spouse_contribution_override, @@ -108,7 +111,6 @@ csgThresholdRouter.put( csl_non_reason_id, csl_over_reason_id, return_uncashable_cert: cleanNumberOptional(return_uncashable_cert), - over_award: cleanNumberOptional(over_award), student_contribution_override: cleanNumberOptional(student_contribution_override), spouse_contribution_override: cleanNumberOptional(spouse_contribution_override), parent_contribution_override: cleanNumberOptional(parent_contribution_override), @@ -136,7 +138,6 @@ csgThresholdRouter.put( assessed_amount: calced.assessed_amount, csl_assessed_need: calced.csl_assessed_need, return_uncashable_cert: cleanNumberOptional(return_uncashable_cert), - over_award: cleanNumberOptional(over_award), student_contribution_override: cleanNumberOptional(student_contribution_override), spouse_contribution_override: cleanNumberOptional(spouse_contribution_override), parent_contribution_override: cleanNumberOptional(parent_contribution_override), @@ -164,7 +165,6 @@ csgThresholdRouter.put( (recalc as any).student_contribution_override = null; (recalc as any).spouse_contribution_override = null; (recalc as any).parent_contribution_override = null; - (recalc as any).over_award = null; (recalc as any).return_uncashable_cert = null; (recalc as any).csl_non_reason_id = null; (recalc as any).csl_over_reason_id = null; @@ -197,9 +197,6 @@ csgThresholdRouter.post( if (!loaded) return res.status(500).send("Error loading assessment"); - let existingOveraward = student.pre_over_award_amount ?? 0; - existingOveraward += Math.abs(loaded.net_amount); - const amount = Math.round(loaded.net_amount * 100) / 100; await db("sfa.overaward").insert({ @@ -213,8 +210,6 @@ csgThresholdRouter.post( amount, }); - //await db("sfa.student").where({ id: application.student_id }).update({ pre_over_award_amount: existingOveraward }); - //await db("sfa.assessment").where({ id: assessment_id }).update(recalc); return res.status(200).json({ data: "Assessment Saved" }); } @@ -238,10 +233,38 @@ csgThresholdRouter.post( if (!loaded) return res.status(500).send("Error loading assessment"); - let existingOveraward = student.pre_over_award_amount ?? 0; - existingOveraward -= Math.abs(loaded.net_amount); + if (loaded.net_overaward < 0 && loaded.net_amount > 0) { + const toClear = Math.min(loaded.net_amount, Math.abs(loaded.net_overaward)); + + await db("sfa.overaward").insert({ + student_id: student.id, + academic_year_id: application.academic_year_id, + application_id: fundingRequest.application_id, + funding_request_id, + assessment_id, + created_by: req.user.email, + note: "Created from overaward in CLSFT Assessment", + amount: toClear, + }); + + await db("sfa.assessment").where({ id: assessment_id }).update({ + over_award: toClear, + over_award_applied_flg: "Yes", + }); + + let recalc = await repo.create(funding_request_id, assessment_id); + + delete (recalc as any).id; + delete (recalc as any).assessment_type_id; + (recalc as any).student_contribution_override = null; + (recalc as any).spouse_contribution_override = null; + (recalc as any).parent_contribution_override = null; + (recalc as any).return_uncashable_cert = null; + (recalc as any).csl_non_reason_id = null; + (recalc as any).csl_over_reason_id = null; - await db("sfa.student").where({ id: application.student_id }).update({ pre_over_award_amount: existingOveraward }); + await db("sfa.assessment").where({ id: assessment_id }).update(recalc); + } return res.status(200).json({ data: "Assessment Saved" }); } diff --git a/src/web/src/components/application/assessments/components/csl-ft/tab-award.vue b/src/web/src/components/application/assessments/components/csl-ft/tab-award.vue index 1129c73a..652e05d2 100644 --- a/src/web/src/components/application/assessments/components/csl-ft/tab-award.vue +++ b/src/web/src/components/application/assessments/components/csl-ft/tab-award.vue @@ -169,7 +169,7 @@ Disburse + + This student has an outstanding overaward balance. + + + This assessment has an overward applied. + + + This assessment has an overward recorded. + diff --git a/src/web/src/components/application/assessments/store/csl-full-time.js b/src/web/src/components/application/assessments/store/csl-full-time.js index 4c1f7a38..8a162477 100644 --- a/src/web/src/components/application/assessments/store/csl-full-time.js +++ b/src/web/src/components/application/assessments/store/csl-full-time.js @@ -238,19 +238,25 @@ const actions = { }); }, - async clearOveraward() { + async clearOveraward({ dispatch }) { console.log("CLEARING OVERAWRD"); let url = `${CSG_THRESHOLD_URL}/funding-request/${state.fundingRequest.id}/assessment/${state.assessment.id}/clear-overaward`; return axios.post(url).then(async (resp) => { - console.log("RESP", resp); + dispatch("loadCSLFTAssessment", { + applicationId: state.fundingRequest.application_id, + assessmentId: state.assessment.id, + }); }); }, - async recordOveraward({ state }) { + async recordOveraward({ dispatch, state }) { let url = `${CSG_THRESHOLD_URL}/funding-request/${state.fundingRequest.id}/assessment/${state.assessment.id}/record-overaward`; return axios.post(url).then(async (resp) => { - console.log("RESP", resp); + dispatch("loadCSLFTAssessment", { + applicationId: state.fundingRequest.application_id, + assessmentId: state.assessment.id, + }); }); }, async deleteAssessment() { diff --git a/src/web/src/components/application/assessments/views/CSLFT.vue b/src/web/src/components/application/assessments/views/CSLFT.vue index 254419f6..e46b0946 100644 --- a/src/web/src/components/application/assessments/views/CSLFT.vue +++ b/src/web/src/components/application/assessments/views/CSLFT.vue @@ -12,9 +12,9 @@ Total Awarded: {{ totalAwarded }} - {{ percentAwarded }} of Need + > --> mdi-pin-outline Record Overaward - + mdi-eraser - Clear Student Overaward + Apply Student Overaward mdi-trash-can-outline @@ -76,7 +76,7 @@ >CSG-PTDEP
{{ formatMoney(depAmount) }} --> - Award
{{ formatMoney(assessment.net_amount) }}
+ Award
{{ formatMoney(assessment.assessed_amount) }}
MSFAA @@ -188,10 +188,11 @@ export default { ...mapState("cslFullTimeStore", ["isLoading", "assessment", "fundingRequest", "disbursements", "msfaa"]), ...mapGetters(["cslClassifications", "disbursementTypes", "changeReasons"]), totalAwarded() { - return this.formatMoney(this.assessment.net_amount); + // this should be a sum of all disbursements amounts for all assessments + return this.formatMoney(this.assessment.assessed_amount); }, percentAwarded() { - return `${Math.round((100 * this.assessment.net_amount) / this.assessment.total_costs)}%`; + return `${Math.round((100 * this.assessment.assessed_amount) / this.assessment.total_costs)}%`; }, assessmentItems() { if (this.fundingRequest) { @@ -237,11 +238,21 @@ export default { canAddAssessment() { return this.canSave && this.disbursements.length > 0; }, - canClearOveraward() { - return this.assessment.over_award && this.assessment.over_award > 0; + canApplyOveraward() { + return ( + this.assessment.id && + this.canSave && + this.assessment.net_amount > 0 && + !(this.assessment.has_overaward_applied || this.assessment.has_overaward_recorded) + ); }, canRecordOveraward() { - return this.canSave && this.assessment.net_amount < 0 && (this.student.pre_over_award_amount ?? 0) < 1; + return ( + this.assessment.id && + this.canSave && + this.assessment.net_amount < 0 && + !(this.assessment.has_overaward_applied || this.assessment.has_overaward_recorded) + ); }, canDelete() { return this.disbursements.length == 0; @@ -304,16 +315,23 @@ export default { async addAssessmentClick() { await this.createAssessment(); }, - async clearOverawardClick() { + async applyOverawardClick() { await this.clearOveraward(); }, async recordOverawardClick() { - await this.recordOveraward(); + await this.recordOveraward().then(() => { + this.showSuccess("Overaward recorded"); + }); }, async deleteClick() { - await this.deleteAssessment().then((resp) => { - this.$router.push(`/application/${this.application.id}/cslft/${this.fundingRequest.id}`); - }); + await this.deleteAssessment() + .then((resp) => { + this.$router.push(`/application/${this.application.id}/cslft/${this.fundingRequest.id}`); + }) + .catch((err) => { + console.log(err); + this.showError(err.response.data.error); + }); }, }, }; diff --git a/src/web/src/components/student/Screening.vue b/src/web/src/components/student/Screening.vue index cdd02c13..3911ae3f 100644 --- a/src/web/src/components/student/Screening.vue +++ b/src/web/src/components/student/Screening.vue @@ -84,8 +84,7 @@