Skip to content

Commit 4273203

Browse files
committed
Use generic D5-X report structure instead of specific D5-3
1 parent 08a4e16 commit 4273203

File tree

6 files changed

+130
-104
lines changed

6 files changed

+130
-104
lines changed

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

Lines changed: 7 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,74 +2,26 @@ package hmda.publication.reports.disclosure
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 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-
2510
object D53 {
26-
val metaData = ReportsMetaDataLookup.values("D53")
27-
val dispositions = metaData.dispositions
2811

29-
// Table filters:
30-
// Property Type: 1, 2
31-
// Purpose of Loan: 3
12+
def filters(lar: LoanApplicationRegisterQuery): Boolean = {
13+
(lar.propertyType == 1 || lar.propertyType == 2) &&
14+
(lar.purpose == 3)
15+
}
16+
3217
def generate[ec: EC, mat: MAT, as: AS](
3318
larSource: Source[LoanApplicationRegisterQuery, NotUsed],
3419
fipsCode: Int,
3520
respondentId: String,
3621
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 {
22+
): Future[Series5DisclosureReport] = {
6323

64-
D53(
65-
respondentId,
66-
institutionName,
67-
year,
68-
msa,
69-
applicantIncomes,
70-
total
71-
)
72-
}
24+
D5X.generate("D53", filters, larSource, fipsCode, respondentId, institutionNameF)
7325

7426
}
7527

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

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
package hmda.publication.reports.disclosure
22

3-
import hmda.model.publication.reports.{ MSAReport, ReportTypeEnum }
3+
import hmda.publication.reports._
4+
import hmda.model.publication.reports.{ ApplicantIncome, Disposition, MSAReport, ReportTypeEnum }
45
import hmda.model.publication.reports.ReportTypeEnum.Disclosure
6+
import hmda.publication.reports.util.ReportsMetaDataLookup
7+
import hmda.publication.reports.util.ReportUtil._
8+
import akka.NotUsed
9+
import akka.stream.scaladsl.Source
10+
import hmda.query.model.filing.LoanApplicationRegisterQuery
11+
12+
import scala.concurrent.Future
513

614
trait DisclosureReport {
715

@@ -11,7 +19,71 @@ trait DisclosureReport {
1119
val table: String
1220
val year: Int
1321
val msa: MSAReport
22+
val reportDate: String
1423

1524
val reportType: ReportTypeEnum = Disclosure
1625

1726
}
27+
28+
case class Series5DisclosureReport(
29+
respondentId: String,
30+
institutionName: String,
31+
year: Int,
32+
msa: MSAReport,
33+
applicantIncomes: List[ApplicantIncome],
34+
total: List[Disposition],
35+
table: String,
36+
description: String,
37+
reportDate: String = formattedCurrentDate
38+
) extends DisclosureReport
39+
40+
object D5X {
41+
def generate[ec: EC, mat: MAT, as: AS](
42+
reportId: String,
43+
filters: LoanApplicationRegisterQuery => Boolean,
44+
larSource: Source[LoanApplicationRegisterQuery, NotUsed],
45+
fipsCode: Int,
46+
respondentId: String,
47+
institutionNameF: Future[String]
48+
): Future[Series5DisclosureReport] = {
49+
50+
val metaData = ReportsMetaDataLookup.values(reportId)
51+
val dispositions = metaData.dispositions
52+
53+
val lars = larSource
54+
.filter(lar => lar.respondentId == respondentId)
55+
.filter(lar => lar.msa != "NA")
56+
.filter(lar => lar.msa.toInt == fipsCode)
57+
.filter(filters)
58+
59+
val larsWithIncome = lars.filter(lar => lar.income != "NA")
60+
61+
val msa = msaReport(fipsCode.toString)
62+
63+
val incomeIntervals = incomeIntervalsForMsa(fipsCode)
64+
val applicantIncomesF = applicantIncomesByInterval(larsWithIncome, incomeIntervals, dispositions)
65+
66+
val yearF = reportYear(larSource)
67+
val totalF = calculateDispositions(lars, dispositions)
68+
69+
for {
70+
institutionName <- institutionNameF
71+
year <- yearF
72+
applicantIncomes <- applicantIncomesF
73+
total <- totalF
74+
} yield {
75+
76+
Series5DisclosureReport(
77+
respondentId,
78+
institutionName,
79+
year,
80+
msa,
81+
applicantIncomes,
82+
total,
83+
metaData.reportTable,
84+
metaData.description
85+
)
86+
}
87+
88+
}
89+
}

publication/src/main/scala/hmda/publication/reports/protocol/disclosure/D53Protocol.scala renamed to publication/src/main/scala/hmda/publication/reports/protocol/disclosure/D5XProtocol.scala

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,24 @@ package hmda.publication.reports.protocol.disclosure
22

33
import hmda.model.publication.reports.{ ApplicantIncome, Disposition, MSAReport }
44
import hmda.model.publication.reports.ReportTypeEnum.Disclosure
5-
import hmda.publication.reports.disclosure.D53
5+
import hmda.publication.reports.disclosure.Series5DisclosureReport
66
import hmda.publication.reports.protocol.{ ApplicantIncomeProtocol, MSAReportProtocol, ReportTypeEnumProtocol }
7-
87
import spray.json._
98
import spray.json.DefaultJsonProtocol
109

11-
object D53Protocol
10+
object D5XProtocol
1211
extends DefaultJsonProtocol
1312
with ReportTypeEnumProtocol
1413
with MSAReportProtocol
1514
with ApplicantIncomeProtocol {
1615

17-
implicit object D53Format extends RootJsonFormat[D53] {
16+
implicit object D5XFormat extends RootJsonFormat[Series5DisclosureReport] {
1817

19-
override def write(obj: D53): JsValue = {
18+
override def write(obj: Series5DisclosureReport): JsValue = {
2019
JsObject(
2120
"respondentId" -> JsString(obj.respondentId),
2221
"institutionName" -> JsString(obj.institutionName),
23-
"table" -> JsString("5-3"),
22+
"table" -> JsString(obj.table),
2423
"type" -> JsString(Disclosure.toString),
2524
"desc" -> JsString(obj.description),
2625
"year" -> JsNumber(obj.year),
@@ -31,23 +30,27 @@ object D53Protocol
3130
)
3231
}
3332

34-
override def read(json: JsValue): D53 = json.asJsObject.getFields(
33+
override def read(json: JsValue): Series5DisclosureReport = json.asJsObject.getFields(
3534
"respondentId",
3635
"institutionName",
3736
"year",
3837
"reportDate",
3938
"msa",
4039
"applicantIncomes",
41-
"total"
40+
"total",
41+
"table",
42+
"desc"
4243
) match {
43-
case Seq(respondentId, institutionName, year, reportDate, msa, applicantIncomes, total) =>
44-
D53(
44+
case Seq(respondentId, institutionName, year, reportDate, msa, applicantIncomes, total, table, desc) =>
45+
Series5DisclosureReport(
4546
respondentId.convertTo[String],
4647
institutionName.convertTo[String],
4748
year.convertTo[Int],
4849
msa.convertTo[MSAReport],
4950
applicantIncomes.convertTo[List[ApplicantIncome]],
5051
total.convertTo[List[Disposition]],
52+
table.convertTo[String],
53+
desc.convertTo[String],
5154
reportDate.convertTo[String]
5255
)
5356
}

publication/src/test/scala/hmda/publication/reports/disclosure/D53ProtocolSpec.scala

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

publication/src/test/scala/hmda/publication/reports/disclosure/DisclosureReportGenerators.scala

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,18 @@ import hmda.publication.reports.util.DateUtil._
77

88
object DisclosureReportGenerators {
99

10-
def d51Gen: Gen[D51] = {
10+
def d5XGen: Gen[Series5DisclosureReport] = {
1111
for {
1212
respId <- Gen.alphaStr
1313
instName <- Gen.alphaStr
1414
year = Calendar.getInstance().get(Calendar.YEAR)
15-
reportDate = formatDate(Calendar.getInstance().toInstant)
1615
msa <- msaReportGen
1716
applicantIncomes <- Gen.listOfN(5, applicantIncomeGen)
1817
total <- totalDispositionGen
19-
} yield D51(respId, instName, year, msa, applicantIncomes, total, reportDate)
18+
} yield Series5DisclosureReport(respId, instName, year, msa, applicantIncomes, total, "D5-X", "description")
2019
}
2120

22-
def d53Gen: Gen[D53] = {
21+
def d51Gen: Gen[D51] = {
2322
for {
2423
respId <- Gen.alphaStr
2524
instName <- Gen.alphaStr
@@ -28,7 +27,7 @@ object DisclosureReportGenerators {
2827
msa <- msaReportGen
2928
applicantIncomes <- Gen.listOfN(5, applicantIncomeGen)
3029
total <- totalDispositionGen
31-
} yield D53(respId, instName, year, msa, applicantIncomes, total, reportDate)
30+
} yield D51(respId, instName, year, msa, applicantIncomes, total, reportDate)
3231
}
3332

3433
}

0 commit comments

Comments
 (0)