Skip to content

Commit 88d1f23

Browse files
committed
Add A5-3 report with generic A5X base
1 parent 19094ed commit 88d1f23

File tree

7 files changed

+116
-90
lines changed

7 files changed

+116
-90
lines changed

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

Lines changed: 6 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,21 @@ package hmda.publication.reports.aggregate
22

33
import akka.NotUsed
44
import akka.stream.scaladsl.Source
5-
import hmda.model.publication.reports.{ ApplicantIncome, Disposition, MSAReport }
65
import hmda.publication.reports._
7-
import hmda.publication.reports.util.ReportUtil._
8-
import hmda.publication.reports.util.ReportsMetaDataLookup
96
import hmda.query.model.filing.LoanApplicationRegisterQuery
107

118
import scala.concurrent.Future
129

13-
case class A53(
14-
year: Int,
15-
msa: MSAReport,
16-
applicantIncomes: List[ApplicantIncome],
17-
total: List[Disposition],
18-
reportDate: String = formattedCurrentDate,
19-
table: String = A53.metaData.reportTable,
20-
description: String = A53.metaData.description
21-
) extends AggregateReport
22-
2310
object A53 {
24-
val metaData = ReportsMetaDataLookup.values("A53")
25-
val dispositions = metaData.dispositions
2611

27-
// Table filters:
28-
// Property Type 1,2
29-
// Purpose of Loan 3
12+
def filters(lar: LoanApplicationRegisterQuery): Boolean = {
13+
(lar.propertyType == 1 || lar.propertyType == 2) &&
14+
(lar.purpose == 3)
15+
}
16+
3017
def generate[ec: EC, mat: MAT, as: AS](
3118
larSource: Source[LoanApplicationRegisterQuery, NotUsed],
3219
fipsCode: Int
33-
): Future[A53] = {
34-
val lars = larSource
35-
.filter(lar => lar.msa != "NA")
36-
.filter(lar => lar.msa.toInt == fipsCode)
37-
.filter { lar =>
38-
(lar.propertyType == 1 || lar.propertyType == 2) &&
39-
(lar.purpose == 3)
40-
}
41-
42-
val larsWithIncome = lars.filter(lar => lar.income != "NA")
43-
44-
val msa = msaReport(fipsCode.toString)
20+
): Future[A5X] = A5X.generate("A53", larSource, fipsCode, filters)
4521

46-
val incomeIntervals = calculateMedianIncomeIntervals(fipsCode)
47-
val applicantIncomesF = applicantIncomesWithBorrowerCharacteristics(larsWithIncome, incomeIntervals, dispositions)
48-
49-
val yearF = calculateYear(larSource)
50-
val totalF = calculateDispositions(lars, dispositions)
51-
52-
for {
53-
applicantIncomes <- applicantIncomesF
54-
year <- yearF
55-
total <- totalF
56-
} yield {
57-
58-
A53(
59-
year,
60-
msa,
61-
applicantIncomes,
62-
total
63-
)
64-
}
65-
}
6622
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package hmda.publication.reports.aggregate
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 A5X(
14+
year: Int,
15+
msa: MSAReport,
16+
applicantIncomes: List[ApplicantIncome],
17+
total: List[Disposition],
18+
table: String,
19+
description: String,
20+
reportDate: String = formattedCurrentDate
21+
) extends AggregateReport
22+
23+
object A5X {
24+
def generate[ec: EC, mat: MAT, as: AS](
25+
reportId: String,
26+
larSource: Source[LoanApplicationRegisterQuery, NotUsed],
27+
fipsCode: Int,
28+
filters: LoanApplicationRegisterQuery => Boolean
29+
): Future[A5X] = {
30+
31+
val metaData = ReportsMetaDataLookup.values(reportId)
32+
val dispositions = metaData.dispositions
33+
34+
val lars = larSource
35+
.filter(lar => lar.msa != "NA")
36+
.filter(lar => lar.msa.toInt == fipsCode)
37+
.filter(filters)
38+
39+
val larsWithIncome = lars.filter(lar => lar.income != "NA")
40+
41+
val msa = msaReport(fipsCode.toString)
42+
43+
val incomeIntervals = calculateMedianIncomeIntervals(fipsCode)
44+
val applicantIncomesF = applicantIncomesWithBorrowerCharacteristics(larsWithIncome, incomeIntervals, dispositions)
45+
46+
val yearF = calculateYear(larSource)
47+
val totalF = calculateDispositions(lars, dispositions)
48+
49+
for {
50+
applicantIncomes <- applicantIncomesF
51+
year <- yearF
52+
total <- totalF
53+
} yield {
54+
55+
A5X(
56+
year,
57+
msa,
58+
applicantIncomes,
59+
total,
60+
metaData.reportTable,
61+
metaData.description
62+
)
63+
}
64+
}
65+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ trait AggregateReport {
99
val description: String
1010
val year: Int
1111
val msa: MSAReport
12+
val reportDate: String
1213

1314
val reportType: ReportTypeEnum = Aggregate
1415
}

publication/src/main/scala/hmda/publication/reports/protocol/aggregate/A53Protocol.scala renamed to publication/src/main/scala/hmda/publication/reports/protocol/aggregate/A5XProtocol.scala

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@ package hmda.publication.reports.protocol.aggregate
22

33
import hmda.model.publication.reports.{ ApplicantIncome, Disposition, MSAReport }
44
import hmda.model.publication.reports.ReportTypeEnum._
5-
import hmda.publication.reports.aggregate.A53
5+
import hmda.publication.reports.aggregate.A5X
66
import hmda.publication.reports.protocol.{ ApplicantIncomeProtocol, MSAReportProtocol, ReportTypeEnumProtocol }
77
import spray.json._
88

9-
object A53Protocol
9+
object A5XProtocol
1010
extends DefaultJsonProtocol
1111
with ReportTypeEnumProtocol
1212
with MSAReportProtocol
1313
with ApplicantIncomeProtocol {
1414

15-
implicit object A53Format extends RootJsonFormat[A53] {
16-
override def write(obj: A53): JsValue = {
15+
implicit object A5XFormat extends RootJsonFormat[A5X] {
16+
override def write(obj: A5X): JsValue = {
1717
JsObject(
18-
"table" -> JsString("5-3"),
18+
"table" -> JsString(obj.table),
1919
"type" -> JsString(Aggregate.toString),
2020
"desc" -> JsString(obj.description),
2121
"year" -> JsNumber(obj.year),
@@ -26,7 +26,7 @@ object A53Protocol
2626
)
2727
}
2828

29-
override def read(json: JsValue): A53 = json.asJsObject.getFields(
29+
override def read(json: JsValue): A5X = json.asJsObject.getFields(
3030
"table",
3131
"type",
3232
"desc",
@@ -37,11 +37,13 @@ object A53Protocol
3737
"total"
3838
) match {
3939
case Seq(table, reportType, description, year, reportDate, msa, applicantIncomes, total) =>
40-
A53(
40+
A5X(
4141
year.convertTo[Int],
4242
msa.convertTo[MSAReport],
4343
applicantIncomes.convertTo[List[ApplicantIncome]],
4444
total.convertTo[List[Disposition]],
45+
table.convertTo[String],
46+
description.convertTo[String],
4547
reportDate.convertTo[String]
4648
)
4749
}

publication/src/test/scala/hmda/publication/reports/aggregate/A53ProtocolSpec.scala

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package hmda.publication.reports.aggregate
2+
3+
import hmda.publication.reports.protocol.aggregate.A5XProtocol._
4+
import org.scalatest.{ MustMatchers, PropSpec }
5+
import org.scalatest.prop.PropertyChecks
6+
import spray.json._
7+
import AggregateReportGenerators._
8+
9+
class A5XProtocolSpec extends PropSpec with PropertyChecks with MustMatchers {
10+
11+
property("A5X Report must convert to and from JSON") {
12+
forAll(a5XGen) { a5X =>
13+
a5X.toJson.convertTo[A5X] mustBe a5X
14+
}
15+
}
16+
17+
property("A5X Report must serialize to the correct JSON format") {
18+
forAll(a5XGen) { a5X =>
19+
a5X.toJson mustBe JsObject(
20+
"table" -> JsString(a5X.table),
21+
"type" -> JsString("Aggregate"),
22+
"desc" -> JsString(a5X.description),
23+
"year" -> JsNumber(a5X.year),
24+
"reportDate" -> JsString(a5X.reportDate),
25+
"msa" -> a5X.msa.toJson,
26+
"applicantIncomes" -> a5X.applicantIncomes.toJson,
27+
"total" -> a5X.total.toJson
28+
)
29+
}
30+
}
31+
}

publication/src/test/scala/hmda/publication/reports/aggregate/AggregateReportGenerators.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ object AggregateReportGenerators {
1717
} yield A52(year, msa, applicantIncomes, total, reportDate)
1818
}
1919

20-
implicit def a53Gen: Gen[A53] = {
20+
implicit def a5XGen: Gen[A5X] = {
2121
for {
2222
msa <- msaReportGen
2323
year = Calendar.getInstance().get(Calendar.YEAR)
2424
reportDate = formatDate(Calendar.getInstance().toInstant)
2525
applicantIncomes <- Gen.listOfN(5, applicantIncomeGen)
26+
table <- Gen.alphaStr
27+
description <- Gen.alphaStr
2628
total <- totalDispositionGen
27-
} yield A53(year, msa, applicantIncomes, total, reportDate)
29+
} yield A5X(year, msa, applicantIncomes, total, table, description, reportDate)
2830
}
2931
}

0 commit comments

Comments
 (0)