Created
April 26, 2020 09:51
-
-
Save juliano/042748ba547b72b8cf6445782edb8896 to your computer and use it in GitHub Desktop.
Matching invoices
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object Exercise { | |
sealed trait InvoiceType | |
case object Approved extends InvoiceType | |
case object UnApproved extends InvoiceType | |
type Money = Double | |
type FundingFacilityId = String | |
case class Invoice(`type`: InvoiceType, amount: Money) | |
case class FundingFacility(id: FundingFacilityId, | |
fundedInvoiceTypes: List[InvoiceType], | |
limit: Option[Money], | |
totalDrawnDownAmount: Money) { | |
def updateDrawnAmount(invoice: Invoice) = | |
copy(totalDrawnDownAmount = this.totalDrawnDownAmount + invoice.amount) | |
} | |
def fundingFacilitySelector(invoices: List[Invoice], | |
fundingFacilities: List[FundingFacility] | |
): List[(Invoice, FundingFacilityId)] = { | |
val seed = (fundingFacilities, List.empty[(Invoice, FundingFacilityId)]) | |
invoices.foldLeft(seed) { (acc, invoice) => | |
val (ffs, matchedInvoices) = acc | |
val opt = for { | |
theFF <- suitableFF(ffs, invoice) | |
updatedFFs = updatedFundingFacilities(ffs, theFF, invoice) | |
newMatch = (invoice, theFF.id) | |
} yield (updatedFFs, matchedInvoices :+ newMatch) | |
opt.getOrElse(throw new RuntimeException("Couldn't find a suitable Funding Facility")) | |
}._2 | |
} | |
private def suitableFF(ffs: List[FundingFacility], invoice: Invoice) = | |
ffs.find { f => | |
f.fundedInvoiceTypes.contains(invoice.`type`) && | |
f.limit.exists(_ - f.totalDrawnDownAmount >= invoice.amount) | |
} | |
private def updatedFundingFacilities(ffs: List[FundingFacility], | |
f: FundingFacility, | |
i: Invoice): List[FundingFacility] = { | |
val index = ffs.indexWhere(_ == f) | |
ffs.updated(index, f.updateDrawnAmount(i)) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Exercise._ | |
import zio.test.Assertion.equalTo | |
import zio.test.{DefaultRunnableSpec, assert, suite, test} | |
object ExerciseSpec extends DefaultRunnableSpec { | |
def spec = suite("Exercise Suite")( | |
selectFFSuite | |
) | |
val inv1 = Invoice(Approved, 1000.0) | |
val inv2 = Invoice(Approved, 100.0) | |
val inv3 = Invoice(UnApproved, 100.0) | |
val inv4 = Invoice(UnApproved, 50.0) | |
val inv5 = Invoice(Approved, 150.0) | |
val inv6 = Invoice(UnApproved, 150.0) | |
val allInvoices = List(inv1, inv2, inv3, inv4, inv5, inv6) | |
val ff1 = FundingFacility("f1", List(Approved), Some(200.0), 0.0) | |
val ff2 = FundingFacility("f2", List(UnApproved), Some(200.0), 0.0) | |
val emergencyFF = FundingFacility("emergency", List(Approved, UnApproved), Some(Double.MaxValue), 0.0) | |
val fundingFacilities = List(ff1, ff2, emergencyFF) | |
val selectFFSuite = suite("Select Funding Facility")( | |
test("approved") { | |
val result = fundingFacilitySelector(List(inv2), fundingFacilities) | |
val expected = List[(Invoice, FundingFacilityId)]( | |
(inv2, "f1") | |
) | |
assert(result)(equalTo(expected)) | |
}, | |
test("approved and unaproved") { | |
val result = fundingFacilitySelector(List(inv2, inv3), fundingFacilities) | |
val expected = List[(Invoice, FundingFacilityId)]( | |
(inv2, "f1"), | |
(inv3, "f2") | |
) | |
assert(result)(equalTo(expected)) | |
}, | |
test("consumes limit") { | |
val result = fundingFacilitySelector(List(inv3, inv4, inv6), fundingFacilities) | |
val expected = List[(Invoice, FundingFacilityId)]( | |
(inv3, "f2"), | |
(inv4, "f2"), | |
(inv6, "emergency") | |
) | |
assert(result)(equalTo(expected)) | |
}, | |
test("matches different invoices to ffs") { | |
val result = fundingFacilitySelector(allInvoices, fundingFacilities) | |
val expected = List[(Invoice, FundingFacilityId)]( | |
(inv1, "emergency"), | |
(inv2, "f1"), | |
(inv3, "f2"), | |
(inv4, "f2"), | |
(inv5, "emergency"), | |
(inv6, "emergency") | |
) | |
assert(result)(equalTo(expected)) | |
} | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment