Implement contracts
This commit is contained in:
parent
31014d1a0c
commit
efdc50eb1d
33 changed files with 879 additions and 173 deletions
24
api/src/lu/foyer/contracts/ContractController.scala
Normal file
24
api/src/lu/foyer/contracts/ContractController.scala
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package lu.foyer
|
||||
package contracts
|
||||
|
||||
import zio.*
|
||||
import zio.Console.*
|
||||
import zio.http.*
|
||||
import zio.http.codec.*
|
||||
import zio.http.codec.PathCodec.path
|
||||
import zio.http.endpoint.*
|
||||
import zio.schema.*
|
||||
|
||||
import java.net.URI
|
||||
import java.time.LocalDate
|
||||
import java.util.UUID
|
||||
|
||||
class ContractController(
|
||||
val commandEngine: CommandEngine[ContractCommand, ContractEvent, ContractState])
|
||||
extends CommandEngineController[ContractCommand, ContractEvent, ContractState]:
|
||||
override val onthology = "org:example:insurance:contract"
|
||||
override val entityName = "contracts"
|
||||
override val allEntities = List("clients", "contracts")
|
||||
|
||||
object ContractController:
|
||||
val layer = ZLayer.fromFunction(ContractController.apply)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package lu.foyer
|
||||
package contracts
|
||||
|
||||
import java.util.UUID
|
||||
import zio.*
|
||||
|
||||
class ContractEventRepositoryInMemory(events: Ref[Map[UUID, Event[ContractEvent]]])
|
||||
extends EventRepository[ContractEvent]
|
||||
with InMemoryRepository[Event[ContractEvent]](events):
|
||||
def fetchOne(entityId: UUID, eventId: UUID): Task[Option[Event[ContractEvent]]] =
|
||||
events.get.map(_.get(eventId))
|
||||
def fetchMany(entityId: UUID, page: Page): Task[Paged[Event[ContractEvent]]] =
|
||||
events.get
|
||||
.map(entities =>
|
||||
val items = entities.values
|
||||
.filter(_.entityId == entityId)
|
||||
.drop(page.number.getOrElse(0) * page.size.getOrElse(50))
|
||||
.take(page.size.getOrElse(50))
|
||||
Paged(items.toList, if page.totals.getOrElse(false) then Some(entities.size) else None)
|
||||
)
|
||||
|
||||
object ContractEventRepositoryInMemory:
|
||||
val layer = ZLayer.fromZIO(Ref.make(Map.empty).map(ContractEventRepositoryInMemory(_)))
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package lu.foyer
|
||||
package contracts
|
||||
|
||||
import java.util.UUID
|
||||
import zio.*
|
||||
|
||||
class ContractStateRepositoryInMemory(clients: Ref[Map[UUID, Entity[ContractState]]])
|
||||
extends StateRepository[ContractState]
|
||||
with InMemoryRepository[Entity[ContractState]](clients)
|
||||
|
||||
object ContractStateRepositoryInMemory:
|
||||
val layer = ZLayer.fromZIO(Ref.make(Map.empty).map(ContractStateRepositoryInMemory(_)))
|
||||
24
api/src/lu/foyer/contracts/EmployeeServiceImpl.scala
Normal file
24
api/src/lu/foyer/contracts/EmployeeServiceImpl.scala
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package lu.foyer
|
||||
package contracts
|
||||
|
||||
import java.util.UUID
|
||||
import zio.*
|
||||
import lu.foyer.clients.Address
|
||||
import scala.math.BigDecimal.RoundingMode
|
||||
import java.util.Currency
|
||||
import lu.foyer.clients.Country
|
||||
|
||||
object EmployeeServiceImpl extends EmployeeService:
|
||||
|
||||
def fetchOne(subject: String): Either[String, Employee] =
|
||||
if subject == "usr:top" then
|
||||
Right(
|
||||
Employee(
|
||||
subject,
|
||||
EmployeeDisplayName.assume("MEIER Christoph"),
|
||||
Email.assume("top@foyer.lu")
|
||||
)
|
||||
)
|
||||
else Left("Invalid Employee")
|
||||
|
||||
val layer = ZLayer.succeed(EmployeeServiceImpl)
|
||||
53
api/src/lu/foyer/contracts/PremiumServiceImpl.scala
Normal file
53
api/src/lu/foyer/contracts/PremiumServiceImpl.scala
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package lu.foyer
|
||||
package contracts
|
||||
|
||||
import java.util.UUID
|
||||
import zio.*
|
||||
import lu.foyer.clients.Address
|
||||
import scala.math.BigDecimal.RoundingMode
|
||||
import java.util.Currency
|
||||
import lu.foyer.clients.Country
|
||||
|
||||
object PremiumServiceImpl extends PremiumService:
|
||||
private val EUR = Currency.getInstance("EUR")
|
||||
|
||||
private val brands =
|
||||
Map(
|
||||
"renault" -> BigDecimal(0.5),
|
||||
"fiat" -> BigDecimal(0.6),
|
||||
"ford" -> BigDecimal(0.7),
|
||||
"nissan" -> BigDecimal(0.75),
|
||||
"peugeot" -> BigDecimal(0.8),
|
||||
"volkswagen" -> BigDecimal(1.1),
|
||||
"audi" -> BigDecimal(1.25),
|
||||
"bmw" -> BigDecimal(1.25),
|
||||
"mercedes" -> BigDecimal(1.25),
|
||||
"ferrari" -> BigDecimal(2.3),
|
||||
"bugatti" -> BigDecimal(2.6),
|
||||
"tesla" -> BigDecimal(5.0)
|
||||
)
|
||||
|
||||
private val countries =
|
||||
Map(Country.CH -> BigDecimal(0.8), Country.LU -> BigDecimal(1.2))
|
||||
|
||||
private def computeAmountEUR(base: BigDecimal, brand: VehicleBrand, country: Country)
|
||||
: BigDecimal =
|
||||
val brandMultiplier = brands.getOrElse(brand.toLowerCase, BigDecimal(1))
|
||||
val countryMultiplier = countries.getOrElse(country, BigDecimal(1))
|
||||
val amount = base * brandMultiplier * countryMultiplier
|
||||
amount.setScale(EUR.getDefaultFractionDigits, RoundingMode.HALF_UP).rounded
|
||||
|
||||
override def computePremium(formula: FormulaType, vehicle: Vehicle, residentialAddress: Address)
|
||||
: Either[String, Amount] =
|
||||
if vehicle.insuredValue.value > formula.maxCoverage then
|
||||
Left(s"The $formula formula only covers amounts up to ${formula.maxCoverage} EUR")
|
||||
else
|
||||
Right(
|
||||
Amount(
|
||||
computeAmountEUR(formula.basePremium, vehicle.brand, residentialAddress.country),
|
||||
EUR
|
||||
)
|
||||
)
|
||||
|
||||
val layer = ZLayer.succeed(PremiumServiceImpl)
|
||||
end PremiumServiceImpl
|
||||
Loading…
Add table
Add a link
Reference in a new issue