Skip to content

Commit c547b14

Browse files
author
Nick Grippin
committed
A52, generators, and protocol implemented
1 parent 0b4d02a commit c547b14

File tree

5 files changed

+248
-0
lines changed

5 files changed

+248
-0
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package hmda.publication.reports.aggregate
2+
3+
import java.util.Calendar
4+
5+
import akka.NotUsed
6+
import akka.stream.scaladsl.Source
7+
import hmda.model.publication.reports.ApplicantIncomeEnum._
8+
import hmda.model.publication.reports.{ ApplicantIncome, Disposition, MSAReport }
9+
import hmda.publication.reports._
10+
import hmda.publication.reports.util.DateUtil._
11+
import hmda.publication.reports.util.DispositionType.{ ClosedDisp, WithdrawnDisp, _ }
12+
import hmda.publication.reports.util.ReportUtil._
13+
import hmda.query.model.filing.LoanApplicationRegisterQuery
14+
15+
import scala.concurrent.Future
16+
17+
case class A52(
18+
table: String,
19+
description: String,
20+
year: Int,
21+
reportDate: String,
22+
msa: MSAReport,
23+
applicantIncomes: List[ApplicantIncome],
24+
total: List[Disposition]
25+
) extends AggregateReport
26+
27+
object A52 {
28+
def apply(
29+
year: Int,
30+
reportDate: String,
31+
msa: MSAReport,
32+
applicantIncomes: List[ApplicantIncome],
33+
total: List[Disposition]
34+
): A52 = {
35+
36+
val description = "Disposition of Applications for Conventional Home-Purchase Loans, 1-to-4 Family and Manufactured Home Dwellings, by Income, Race, and Ethnicity of Applicant"
37+
38+
A52(
39+
"5-2",
40+
description,
41+
year,
42+
reportDate,
43+
msa,
44+
applicantIncomes,
45+
total
46+
)
47+
}
48+
49+
val dispositions: List[DispositionType] =
50+
List(
51+
ReceivedDisp,
52+
OriginatedDisp,
53+
ApprovedButNotAcceptedDisp,
54+
DeniedDisp,
55+
WithdrawnDisp,
56+
ClosedDisp
57+
)
58+
59+
// Table filters:
60+
// Loan Type 1
61+
// Property Type 1,2
62+
// Purpose of Loan 1
63+
def generate[ec: EC, mat: MAT, as: AS](
64+
larSource: Source[LoanApplicationRegisterQuery, NotUsed],
65+
fipsCode: Int
66+
): Future[A52] = {
67+
val lars = larSource
68+
.filter(lar => lar.msa != "NA")
69+
.filter(lar => lar.msa.toInt == fipsCode)
70+
.filter { lar =>
71+
(lar.loanType == 1) &&
72+
(lar.propertyType == 1 || lar.propertyType == 2) &&
73+
(lar.purpose == 1)
74+
}
75+
76+
val larsWithIncome = lars.filter(lar => lar.income != "NA")
77+
78+
val msa = msaReport(fipsCode.toString)
79+
80+
val incomeIntervals = calculateMedianIncomeIntervals(fipsCode)
81+
82+
val larsByIncome = larsByIncomeInterval(larsWithIncome, incomeIntervals)
83+
val borrowerCharacteristicsByIncomeF = borrowerCharacteristicsByIncomeInterval(larsByIncome, dispositions)
84+
85+
val dateF = calculateYear(larSource)
86+
val totalF = calculateDispositions(lars, dispositions)
87+
88+
for {
89+
lars50BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(LessThan50PercentOfMSAMedian)
90+
lars50To79BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(Between50And79PercentOfMSAMedian)
91+
lars80To99BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(Between80And99PercentOfMSAMedian)
92+
lars100To120BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(Between100And119PercentOfMSAMedian)
93+
lars120BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(GreaterThan120PercentOfMSAMedian)
94+
95+
date <- dateF
96+
total <- totalF
97+
} yield {
98+
val income50 = ApplicantIncome(
99+
LessThan50PercentOfMSAMedian,
100+
lars50BorrowerCharacteristics
101+
)
102+
val income50To79 = ApplicantIncome(
103+
Between50And79PercentOfMSAMedian,
104+
lars50To79BorrowerCharacteristics
105+
)
106+
val income80To99 = ApplicantIncome(
107+
Between80And99PercentOfMSAMedian,
108+
lars80To99BorrowerCharacteristics
109+
)
110+
val income100To120 = ApplicantIncome(
111+
Between100And119PercentOfMSAMedian,
112+
lars100To120BorrowerCharacteristics
113+
)
114+
val income120 = ApplicantIncome(
115+
GreaterThan120PercentOfMSAMedian,
116+
lars120BorrowerCharacteristics
117+
)
118+
119+
A52(
120+
date,
121+
formatDate(Calendar.getInstance().toInstant),
122+
msa,
123+
List(
124+
income50,
125+
income50To79,
126+
income80To99,
127+
income100To120,
128+
income120
129+
),
130+
total
131+
)
132+
}
133+
}
134+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package hmda.publication.reports.aggregate
2+
3+
import hmda.model.publication.reports.{ MSAReport, ReportTypeEnum }
4+
import hmda.model.publication.reports.ReportTypeEnum.Aggregate
5+
6+
trait AggregateReport {
7+
8+
val table: String
9+
val description: String
10+
val year: Int
11+
val msa: MSAReport
12+
13+
val reportType: ReportTypeEnum = Aggregate
14+
}
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 akka.actor.ActorSystem
4+
import akka.stream.ActorMaterializer
5+
import akka.util.Timeout
6+
import com.typesafe.config.ConfigFactory
7+
import hmda.query.repository.filing.FilingCassandraRepository
8+
import hmda.publication.reports.protocol.aggregate.A52Protocol._
9+
10+
import scala.concurrent.Future
11+
import scala.concurrent.duration._
12+
13+
import spray.json._
14+
15+
class AggregateReports(val sys: ActorSystem, val mat: ActorMaterializer) extends FilingCassandraRepository {
16+
17+
override implicit def system: ActorSystem = sys
18+
override implicit def materializer: ActorMaterializer = mat
19+
val config = ConfigFactory.load()
20+
val duration = config.getInt("hmda.actor-lookup-timeout")
21+
implicit val timeout = Timeout(duration.seconds)
22+
23+
val larSource = readData(1000)
24+
25+
def generateReports(fipsCode: Int): Future[Unit] = {
26+
val a52F = A52.generate(larSource, fipsCode)
27+
a52F.map { a52 =>
28+
println(a52.toJson.prettyPrint)
29+
}
30+
}
31+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package hmda.publication.reports.protocol.aggregate
2+
3+
import hmda.model.publication.reports.{ ApplicantIncome, Disposition, MSAReport }
4+
import hmda.model.publication.reports.ReportTypeEnum._
5+
import hmda.publication.reports.aggregate.A52
6+
import hmda.publication.reports.protocol.{ ApplicantIncomeProtocol, MSAReportProtocol, ReportTypeEnumProtocol }
7+
import spray.json._
8+
9+
object A52Protocol
10+
extends DefaultJsonProtocol
11+
with ReportTypeEnumProtocol
12+
with MSAReportProtocol
13+
with ApplicantIncomeProtocol {
14+
15+
implicit object A52Format extends RootJsonFormat[A52] {
16+
override def write(obj: A52): JsValue = {
17+
JsObject(
18+
"table" -> JsString("5-2"),
19+
"type" -> JsString(Aggregate.toString),
20+
"desc" -> JsString(obj.description),
21+
"year" -> JsNumber(obj.year),
22+
"reportDate" -> JsString(obj.reportDate),
23+
"msa" -> obj.msa.toJson,
24+
"applicantIncomes" -> obj.applicantIncomes.toJson,
25+
"total" -> obj.total.toJson
26+
)
27+
}
28+
29+
override def read(json: JsValue): A52 = json.asJsObject.getFields(
30+
"table",
31+
"type",
32+
"desc",
33+
"year",
34+
"reportDate",
35+
"msa",
36+
"applicantIncomes",
37+
"total"
38+
) match {
39+
case Seq(table, reportType, description, year, reportDate, msa, applicantIncomes, total) =>
40+
A52(
41+
year.convertTo[Int],
42+
reportDate.convertTo[String],
43+
msa.convertTo[MSAReport],
44+
applicantIncomes.convertTo[List[ApplicantIncome]],
45+
total.convertTo[List[Disposition]]
46+
)
47+
}
48+
}
49+
50+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package hmda.publication.reports.aggregate
2+
3+
import java.util.Calendar
4+
5+
import hmda.publication.reports.ReportGenerators._
6+
import hmda.publication.reports.util.DateUtil._
7+
import org.scalacheck.Gen
8+
9+
object AggregateReportGenerators {
10+
implicit def a52Gen: Gen[A52] = {
11+
for {
12+
msa <- msaReportGen
13+
year = Calendar.getInstance().get(Calendar.YEAR)
14+
reportDate = formatDate(Calendar.getInstance().toInstant)
15+
applicantIncomes <- Gen.listOfN(5, applicantIncomeGen)
16+
total <- totalDispositionGen
17+
} yield A52(year, reportDate, msa, applicantIncomes, total)
18+
}
19+
}

0 commit comments

Comments
 (0)