Skip to content

Commit c853f49

Browse files
author
Nick Grippin
authored
Merge pull request cfpb#1144 from schbetsy/D53
D53
2 parents 3bba496 + 5e19f0c commit c853f49

File tree

13 files changed

+319
-93
lines changed

13 files changed

+319
-93
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
ReportId,Type,ReportNumber,Dispositions,Description
1+
ReportId,Type,ReportTable,Dispositions,Description
22
A52,Aggregate,5-2,Received;Originated;ApprovedButNotAccepted;Denied;Withdrawn;Closed,"Disposition of Applications for Conventional Home-Purchase Loans, 1-to-4 Family and Manufactured Home Dwellings, by Income, Race, and Ethnicity of Applicant"
33
D51,Disclosure,5-1,Received;Originated;ApprovedButNotAccepted;Denied;Withdrawn;Closed,"Disposition of applications for FHA, FSA/RHS, and VA home-purchase loans, 1- to 4-family and manufactured home dwellings, by income, race and ethnicity of applicant"
4+
D53,Disclosure,5-3,Received;Originated;ApprovedButNotAccepted;Denied;Withdrawn;Closed,"Disposition of Applications to Refinance Loans on 1-to-4 Family and Manufactured Home Dwellings, by Income, Race, and Ethnicity of Applicant"

publication/src/main/scala/hmda/publication/reports/aggregate/A52.scala

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
package hmda.publication.reports.aggregate
22

3-
import java.util.Calendar
4-
53
import akka.NotUsed
64
import akka.stream.scaladsl.Source
7-
import hmda.model.publication.reports.ApplicantIncomeEnum._
85
import hmda.model.publication.reports.{ ApplicantIncome, Disposition, MSAReport }
96
import hmda.publication.reports._
10-
import hmda.publication.reports.util.DateUtil._
117
import hmda.publication.reports.util.ReportUtil._
128
import hmda.publication.reports.util.ReportsMetaDataLookup
139
import hmda.query.model.filing.LoanApplicationRegisterQuery
@@ -16,10 +12,10 @@ import scala.concurrent.Future
1612

1713
case class A52(
1814
year: Int,
19-
reportDate: String,
2015
msa: MSAReport,
2116
applicantIncomes: List[ApplicantIncome],
2217
total: List[Disposition],
18+
reportDate: String = formattedCurrentDate,
2319
table: String = A52.metaData.reportTable,
2420
description: String = A52.metaData.description
2521
) extends AggregateReport
@@ -50,55 +46,19 @@ object A52 {
5046
val msa = msaReport(fipsCode.toString)
5147

5248
val incomeIntervals = calculateMedianIncomeIntervals(fipsCode)
53-
54-
val larsByIncome = larsByIncomeInterval(larsWithIncome, incomeIntervals)
55-
val borrowerCharacteristicsByIncomeF = borrowerCharacteristicsByIncomeInterval(larsByIncome, dispositions)
49+
val applicantIncomesF = applicantIncomesWithBorrowerCharacteristics(larsWithIncome, incomeIntervals, dispositions)
5650

5751
val yearF = calculateYear(larSource)
5852
val totalF = calculateDispositions(lars, dispositions)
5953

6054
for {
61-
lars50BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(LessThan50PercentOfMSAMedian)
62-
lars50To79BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(Between50And79PercentOfMSAMedian)
63-
lars80To99BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(Between80And99PercentOfMSAMedian)
64-
lars100To120BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(Between100And119PercentOfMSAMedian)
65-
lars120BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(GreaterThan120PercentOfMSAMedian)
66-
55+
applicantIncomes <- applicantIncomesF
6756
year <- yearF
6857
total <- totalF
6958
} yield {
70-
val income50 = ApplicantIncome(
71-
LessThan50PercentOfMSAMedian,
72-
lars50BorrowerCharacteristics
73-
)
74-
val income50To79 = ApplicantIncome(
75-
Between50And79PercentOfMSAMedian,
76-
lars50To79BorrowerCharacteristics
77-
)
78-
val income80To99 = ApplicantIncome(
79-
Between80And99PercentOfMSAMedian,
80-
lars80To99BorrowerCharacteristics
81-
)
82-
val income100To120 = ApplicantIncome(
83-
Between100And119PercentOfMSAMedian,
84-
lars100To120BorrowerCharacteristics
85-
)
86-
val income120 = ApplicantIncome(
87-
GreaterThan120PercentOfMSAMedian,
88-
lars120BorrowerCharacteristics
89-
)
90-
91-
val applicantIncomes = List(
92-
income50,
93-
income50To79,
94-
income80To99,
95-
income100To120,
96-
income120
97-
)
9859

9960
A52(
10061
year,
101-
formatDate(Calendar.getInstance().toInstant),
10262
msa,
10363
applicantIncomes,
10464
total

publication/src/main/scala/hmda/publication/reports/disclosure/D51.scala

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
package hmda.publication.reports.disclosure
22

3-
import java.util.Calendar
4-
53
import akka.NotUsed
64
import akka.stream.scaladsl.Source
7-
import hmda.model.publication.reports.ApplicantIncomeEnum._
85
import hmda.publication.reports._
96
import hmda.model.publication.reports._
10-
import hmda.publication.reports.util.DateUtil._
117
import hmda.publication.reports.util.ReportUtil._
128
import hmda.publication.reports.util.ReportsMetaDataLookup
139
import hmda.query.model.filing.LoanApplicationRegisterQuery
@@ -18,10 +14,10 @@ case class D51(
1814
respondentId: String,
1915
institutionName: String,
2016
year: Int,
21-
reportDate: String,
2217
msa: MSAReport,
2318
applicantIncomes: List[ApplicantIncome],
2419
total: List[Disposition],
20+
reportDate: String = formattedCurrentDate,
2521
table: String = D51.metaData.reportTable,
2622
description: String = D51.metaData.description
2723
) extends DisclosureReport
@@ -55,58 +51,22 @@ object D51 {
5551
val msa = msaReport(fipsCode.toString)
5652

5753
val incomeIntervals = calculateMedianIncomeIntervals(fipsCode)
58-
59-
val larsByIncome = larsByIncomeInterval(larsWithIncome, incomeIntervals)
60-
val borrowerCharacteristicsByIncomeF = borrowerCharacteristicsByIncomeInterval(larsByIncome, dispositions)
54+
val applicantIncomesF = applicantIncomesWithBorrowerCharacteristics(larsWithIncome, incomeIntervals, dispositions)
6155

6256
val yearF = calculateYear(larSource)
6357
val totalF = calculateDispositions(lars, dispositions)
6458

6559
for {
66-
lars50BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(LessThan50PercentOfMSAMedian)
67-
lars50To79BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(Between50And79PercentOfMSAMedian)
68-
lars80To99BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(Between80And99PercentOfMSAMedian)
69-
lars100To120BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(Between100And119PercentOfMSAMedian)
70-
lars120BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(GreaterThan120PercentOfMSAMedian)
71-
7260
institutionName <- institutionNameF
7361
year <- yearF
62+
applicantIncomes <- applicantIncomesF
7463
total <- totalF
7564
} yield {
76-
val income50 = ApplicantIncome(
77-
LessThan50PercentOfMSAMedian,
78-
lars50BorrowerCharacteristics
79-
)
80-
val income50To79 = ApplicantIncome(
81-
Between50And79PercentOfMSAMedian,
82-
lars50To79BorrowerCharacteristics
83-
)
84-
val income80To99 = ApplicantIncome(
85-
Between80And99PercentOfMSAMedian,
86-
lars80To99BorrowerCharacteristics
87-
)
88-
val income100To120 = ApplicantIncome(
89-
Between100And119PercentOfMSAMedian,
90-
lars100To120BorrowerCharacteristics
91-
)
92-
val income120 = ApplicantIncome(
93-
GreaterThan120PercentOfMSAMedian,
94-
lars120BorrowerCharacteristics
95-
)
96-
97-
val applicantIncomes = List(
98-
income50,
99-
income50To79,
100-
income80To99,
101-
income100To120,
102-
income120
103-
)
10465

10566
D51(
10667
respondentId,
10768
institutionName,
10869
year,
109-
formatDate(Calendar.getInstance().toInstant),
11070
msa,
11171
applicantIncomes,
11272
total
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package hmda.publication.reports.disclosure
2+
3+
import akka.NotUsed
4+
import akka.stream.scaladsl.Source
5+
import hmda.model.publication.reports.{ ApplicantIncome, Disposition, MSAReport }
6+
import hmda.publication.reports._
7+
import hmda.publication.reports.util.ReportUtil._
8+
import hmda.publication.reports.util.ReportsMetaDataLookup
9+
import hmda.query.model.filing.LoanApplicationRegisterQuery
10+
11+
import scala.concurrent.Future
12+
13+
case class D53(
14+
respondentId: String,
15+
institutionName: String,
16+
year: Int,
17+
msa: MSAReport,
18+
applicantIncomes: List[ApplicantIncome],
19+
total: List[Disposition],
20+
reportDate: String = formattedCurrentDate,
21+
table: String = D53.metaData.reportTable,
22+
description: String = D53.metaData.description
23+
) extends DisclosureReport
24+
25+
object D53 {
26+
val metaData = ReportsMetaDataLookup.values("D53")
27+
val dispositions = metaData.dispositions
28+
29+
// Table filters:
30+
// Property Type: 1, 2
31+
// Purpose of Loan: 3
32+
def generate[ec: EC, mat: MAT, as: AS](
33+
larSource: Source[LoanApplicationRegisterQuery, NotUsed],
34+
fipsCode: Int,
35+
respondentId: String,
36+
institutionNameF: Future[String]
37+
): Future[D53] = {
38+
39+
val lars = larSource
40+
.filter(lar => lar.respondentId == respondentId)
41+
.filter(lar => lar.msa != "NA")
42+
.filter(lar => lar.msa.toInt == fipsCode)
43+
.filter { lar =>
44+
(lar.propertyType == 1 || lar.propertyType == 2) &&
45+
(lar.purpose == 3)
46+
}
47+
val larsWithIncome = lars.filter(lar => lar.income != "NA")
48+
49+
val msa = msaReport(fipsCode.toString)
50+
51+
val incomeIntervals = calculateMedianIncomeIntervals(fipsCode)
52+
val applicantIncomesF = applicantIncomesWithBorrowerCharacteristics(larsWithIncome, incomeIntervals, dispositions)
53+
54+
val yearF = calculateYear(larSource)
55+
val totalF = calculateDispositions(lars, dispositions)
56+
57+
for {
58+
institutionName <- institutionNameF
59+
year <- yearF
60+
applicantIncomes <- applicantIncomesF
61+
total <- totalF
62+
} yield {
63+
64+
D53(
65+
respondentId,
66+
institutionName,
67+
year,
68+
msa,
69+
applicantIncomes,
70+
total
71+
)
72+
}
73+
74+
}
75+
76+
}

publication/src/main/scala/hmda/publication/reports/disclosure/DisclosureReports.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class DisclosureReports(val sys: ActorSystem, val mat: ActorMaterializer) extend
3333
d51F.map { d51 =>
3434
println(d51.toJson.prettyPrint)
3535
}
36+
37+
//val d53F = D53.generate(larSource, fipsCode, respId, institutionNameF)
3638
}
3739

3840
private def institutionName(respondentId: String): Future[String] = {

publication/src/main/scala/hmda/publication/reports/protocol/aggregate/A52Protocol.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ object A52Protocol
3939
case Seq(table, reportType, description, year, reportDate, msa, applicantIncomes, total) =>
4040
A52(
4141
year.convertTo[Int],
42-
reportDate.convertTo[String],
4342
msa.convertTo[MSAReport],
4443
applicantIncomes.convertTo[List[ApplicantIncome]],
45-
total.convertTo[List[Disposition]]
44+
total.convertTo[List[Disposition]],
45+
reportDate.convertTo[String]
4646
)
4747
}
4848
}

publication/src/main/scala/hmda/publication/reports/protocol/disclosure/D51Protocol.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ object D51Protocol
4747
respondentId.convertTo[String],
4848
institutionName.convertTo[String],
4949
year.convertTo[Int],
50-
reportDate.convertTo[String],
5150
msa.convertTo[MSAReport],
5251
applicantIncomes.convertTo[List[ApplicantIncome]],
53-
total.convertTo[List[Disposition]]
52+
total.convertTo[List[Disposition]],
53+
reportDate.convertTo[String]
5454
)
5555
}
5656
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package hmda.publication.reports.protocol.disclosure
2+
3+
import hmda.model.publication.reports.{ ApplicantIncome, Disposition, MSAReport }
4+
import hmda.model.publication.reports.ReportTypeEnum.Disclosure
5+
import hmda.publication.reports.disclosure.D53
6+
import hmda.publication.reports.protocol.{ ApplicantIncomeProtocol, MSAReportProtocol, ReportTypeEnumProtocol }
7+
8+
import spray.json._
9+
import spray.json.DefaultJsonProtocol
10+
11+
object D53Protocol
12+
extends DefaultJsonProtocol
13+
with ReportTypeEnumProtocol
14+
with MSAReportProtocol
15+
with ApplicantIncomeProtocol {
16+
17+
implicit object D53Format extends RootJsonFormat[D53] {
18+
19+
override def write(obj: D53): JsValue = {
20+
JsObject(
21+
"respondentId" -> JsString(obj.respondentId),
22+
"institutionName" -> JsString(obj.institutionName),
23+
"table" -> JsString("5-3"),
24+
"type" -> JsString(Disclosure.toString),
25+
"desc" -> JsString(obj.description),
26+
"year" -> JsNumber(obj.year),
27+
"reportDate" -> JsString(obj.reportDate),
28+
"msa" -> obj.msa.toJson,
29+
"applicantIncomes" -> obj.applicantIncomes.toJson,
30+
"total" -> obj.total.toJson
31+
)
32+
}
33+
34+
override def read(json: JsValue): D53 = json.asJsObject.getFields(
35+
"respondentId",
36+
"institutionName",
37+
"table",
38+
"type",
39+
"desc",
40+
"year",
41+
"reportDate",
42+
"msa",
43+
"applicantIncomes",
44+
"total"
45+
) match {
46+
case Seq(respondentId, institutionName, table, reportType, description, year, reportDate, msa, applicantIncomes, total) =>
47+
D53(
48+
respondentId.convertTo[String],
49+
institutionName.convertTo[String],
50+
year.convertTo[Int],
51+
msa.convertTo[MSAReport],
52+
applicantIncomes.convertTo[List[ApplicantIncome]],
53+
total.convertTo[List[Disposition]],
54+
reportDate.convertTo[String]
55+
)
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)