Skip to content

Commit 083c5e5

Browse files
author
Nick Grippin
authored
Merge pull request cfpb#1103 from schbetsy/institution-name
Include Institution name in Disclosure reports
2 parents 0a73472 + 6b5c80b commit 083c5e5

File tree

6 files changed

+80
-36
lines changed

6 files changed

+80
-36
lines changed

model/shared/src/main/scala/hmda/model/institution/Institution.scala

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,23 @@ import hmda.model.institution.InstitutionType.UndeterminedInstitutionType
88
* A financial institution, geared towards requirements for filing HMDA data.
99
*/
1010
case class Institution(
11-
id: String,
12-
agency: Agency,
13-
activityYear: Int,
14-
institutionType: InstitutionType,
15-
cra: Boolean,
16-
externalIds: Set[ExternalId],
17-
emailDomains: Set[String],
18-
respondent: Respondent,
19-
hmdaFilerFlag: Boolean,
20-
parent: Parent,
21-
assets: Int,
22-
otherLenderCode: Int,
23-
topHolder: TopHolder
24-
)
11+
id: String,
12+
agency: Agency,
13+
activityYear: Int,
14+
institutionType: InstitutionType,
15+
cra: Boolean,
16+
externalIds: Set[ExternalId],
17+
emailDomains: Set[String],
18+
respondent: Respondent,
19+
hmdaFilerFlag: Boolean,
20+
parent: Parent,
21+
assets: Int,
22+
otherLenderCode: Int,
23+
topHolder: TopHolder
24+
) {
25+
def respondentId: String = respondent.externalId.value
26+
}
27+
2528
case object Institution {
2629
def empty: Institution = Institution(
2730
"",

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,12 @@ object D51 {
6666
// Loan Type 2,3,4
6767
// Property Type 1,2
6868
// Purpose of Loan 1
69-
def generate[ec: EC, mat: MAT, as: AS](larSource: Source[LoanApplicationRegisterQuery, NotUsed], fipsCode: Int, respId: String): Future[D51] = {
69+
def generate[ec: EC, mat: MAT, as: AS](
70+
larSource: Source[LoanApplicationRegisterQuery, NotUsed],
71+
fipsCode: Int,
72+
respId: String,
73+
institutionNameF: Future[String]
74+
): Future[D51] = {
7075

7176
val lars = larSource
7277
.filter(lar => lar.respondentId == respId)
@@ -96,6 +101,7 @@ object D51 {
96101
lars100To120BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(Between100And119PercentOfMSAMedian)
97102
lars120BorrowerCharacteristics <- borrowerCharacteristicsByIncomeF(GreaterThan120PercentOfMSAMedian)
98103

104+
institutionName <- institutionNameF
99105
date <- dateF
100106
total <- totalF
101107
} yield {
@@ -122,7 +128,7 @@ object D51 {
122128

123129
D51(
124130
respId,
125-
"",
131+
institutionName,
126132
date,
127133
formatDate(Calendar.getInstance().toInstant),
128134
msa,
Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,47 @@
11
package hmda.publication.reports.disclosure
22

3-
import akka.actor.ActorSystem
3+
import akka.actor.{ ActorRef, ActorSystem }
4+
import akka.pattern.ask
45
import akka.stream.ActorMaterializer
6+
import akka.util.Timeout
7+
import com.typesafe.config.ConfigFactory
8+
import hmda.model.institution.Institution
9+
import hmda.persistence.model.HmdaSupervisorActor.FindActorByName
510
import hmda.publication.reports.protocol.disclosure.D51Protocol._
611
import hmda.query.repository.filing.FilingCassandraRepository
12+
import hmda.query.view.institutions.InstitutionView
13+
import hmda.query.view.institutions.InstitutionView.GetInstitutionByRespondentId
714

815
import scala.concurrent.Future
16+
import scala.concurrent.duration._
917
import spray.json._
1018

1119
class DisclosureReports(val sys: ActorSystem, val mat: ActorMaterializer) extends FilingCassandraRepository {
1220

1321
override implicit def system: ActorSystem = sys
1422
override implicit def materializer: ActorMaterializer = mat
23+
val config = ConfigFactory.load()
24+
val duration = config.getInt("hmda.actor-lookup-timeout")
25+
implicit val timeout = Timeout(duration.seconds)
1526

1627
val larSource = readData(1000)
1728

1829
def generateReports(fipsCode: Int, respId: String): Future[Unit] = {
19-
val d51F = D51.generate(larSource, fipsCode, respId)
30+
val institutionNameF = institutionName(respId)
31+
32+
val d51F = D51.generate(larSource, fipsCode, respId, institutionNameF)
2033
d51F.map { d51 =>
2134
println(d51.toJson.prettyPrint)
2235
}
2336
}
2437

38+
private def institutionName(respondentId: String): Future[String] = {
39+
val querySupervisor = system.actorSelection("/user/query-supervisor")
40+
val fInstitutionsActor = (querySupervisor ? FindActorByName(InstitutionView.name)).mapTo[ActorRef]
41+
for {
42+
a <- fInstitutionsActor
43+
i <- (a ? GetInstitutionByRespondentId(respondentId)).mapTo[Institution]
44+
} yield i.respondent.name
45+
}
46+
2547
}

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

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@ import hmda.model.publication.reports.{ EthnicityBorrowerCharacteristic, MSARepo
1111
import hmda.query.model.filing.LoanApplicationRegisterQuery
1212
import hmda.query.repository.filing.LarConverter._
1313
import org.scalacheck.Gen
14-
import org.scalatest.{ MustMatchers, WordSpec }
14+
import org.scalatest.{ AsyncWordSpec, MustMatchers }
1515

16-
import scala.concurrent.Await
17-
import scala.concurrent.duration._
16+
import scala.concurrent.Future
1817

19-
class D51Spec extends WordSpec with MustMatchers with LarGenerators {
18+
class D51Spec extends AsyncWordSpec with MustMatchers with LarGenerators {
2019

2120
implicit val system = ActorSystem()
2221
implicit val ec = system.dispatcher
@@ -40,26 +39,28 @@ class D51Spec extends WordSpec with MustMatchers with LarGenerators {
4039
val expectedDispositions = List(ApplicationReceived, LoansOriginated, ApprovedButNotAccepted, ApplicationsDenied, ApplicationsWithdrawn, ClosedForIncompleteness)
4140

4241
"Generate a Disclosure 5-1 report" in {
43-
val result = Await.result(D51.generate(source, fips, respId), 5.seconds)
42+
D51.generate(source, fips, respId, Future("Corvallis Test Bank")).map { result =>
4443

45-
result.msa mustBe MSAReport("18700", "Corvallis, OR", "OR", "Oregon")
46-
result.table mustBe "5-1"
47-
result.respondentId mustBe "98765"
48-
result.applicantIncomes.size mustBe 5
44+
result.msa mustBe MSAReport("18700", "Corvallis, OR", "OR", "Oregon")
45+
result.table mustBe "5-1"
46+
result.respondentId mustBe "98765"
47+
result.institutionName mustBe "Corvallis Test Bank"
48+
result.applicantIncomes.size mustBe 5
4949

50-
val lowestIncome = result.applicantIncomes.head
51-
lowestIncome.applicantIncome mustBe LessThan50PercentOfMSAMedian
50+
val lowestIncome = result.applicantIncomes.head
51+
lowestIncome.applicantIncome mustBe LessThan50PercentOfMSAMedian
5252

53-
val races = lowestIncome.borrowerCharacteristics.head.asInstanceOf[RaceBorrowerCharacteristic].races
54-
races.size mustBe 8
53+
val races = lowestIncome.borrowerCharacteristics.head.asInstanceOf[RaceBorrowerCharacteristic].races
54+
races.size mustBe 8
5555

56-
val ethnicities = lowestIncome.borrowerCharacteristics(1).asInstanceOf[EthnicityBorrowerCharacteristic].ethnicities
57-
ethnicities.size mustBe 4
56+
val ethnicities = lowestIncome.borrowerCharacteristics(1).asInstanceOf[EthnicityBorrowerCharacteristic].ethnicities
57+
ethnicities.size mustBe 4
5858

59-
val minorityStatuses = lowestIncome.borrowerCharacteristics(2).asInstanceOf[MinorityStatusBorrowerCharacteristic].minoritystatus
60-
minorityStatuses.size mustBe 2
59+
val minorityStatuses = lowestIncome.borrowerCharacteristics(2).asInstanceOf[MinorityStatusBorrowerCharacteristic].minoritystatus
60+
minorityStatuses.size mustBe 2
6161

62-
races.head.dispositions.map(_.disposition) mustBe expectedDispositions
62+
races.head.dispositions.map(_.disposition) mustBe expectedDispositions
63+
}
6364
}
6465

6566
}

query/src/main/scala/hmda/query/view/institutions/InstitutionView.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ object InstitutionView {
1919
val name = "institutions-view"
2020

2121
case class GetInstitutionById(institutionId: String) extends Command
22+
case class GetInstitutionByRespondentId(respondentId: String) extends Command
2223
case class GetInstitutionsById(ids: List[String]) extends Command
2324
case class FindInstitutionByPeriodAndDomain(domain: String) extends Command
2425

@@ -63,6 +64,12 @@ class InstitutionView extends HmdaPersistentActor {
6364
val institution = state.institutions.find(i => i.id == institutionId).getOrElse(Institution.empty)
6465
sender() ! institution
6566

67+
case GetInstitutionByRespondentId(respondentId) =>
68+
val institution = state.institutions.find { i =>
69+
i.respondent.externalId.value == respondentId
70+
}.getOrElse(Institution.empty)
71+
sender() ! institution
72+
6673
case GetInstitutionsById(ids) =>
6774
val institutions = state.institutions.filter(i => ids.contains(i.id))
6875
sender() ! institutions

query/src/test/scala/hmda/query/view/institutions/InstitutionViewSpec.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ class InstitutionViewSpec extends ActorSpec {
5656
probe.send(institutionQuery, GetProjectionActorRef)
5757
probe.expectMsgType[ActorRef]
5858
}
59+
60+
"return institution by respondentId" in {
61+
probe.send(institutionQuery, GetInstitutionByRespondentId(i1.respondentId))
62+
probe.expectMsg(i1)
63+
}
5964
}
6065

6166
}

0 commit comments

Comments
 (0)