@@ -4,6 +4,9 @@ import community.flock.eco.workday.ApplicationConstants
44import community.flock.eco.workday.interfaces.Period
55import community.flock.eco.workday.interfaces.filterInRange
66import community.flock.eco.workday.interfaces.inRange
7+ import community.flock.eco.workday.model.AggregationClient
8+ import community.flock.eco.workday.model.AggregationMonth
9+ import community.flock.eco.workday.model.AggregationPerson
710import community.flock.eco.workday.model.Assignment
811import community.flock.eco.workday.model.Contract
912import community.flock.eco.workday.model.ContractExternal
@@ -39,14 +42,14 @@ class AggregationService(
3942 private val applicationConstants : ApplicationConstants
4043) {
4144
42- fun totalPerClient (from : LocalDate , to : LocalDate ): List <Map < String , Any > > {
45+ fun totalPerClient (from : LocalDate , to : LocalDate ): List <AggregationClient > {
4346 val allAssignments = assignmentService.findAllActive(from, to)
4447 return clientService.findAll()
45- .map {
46- client -> mapOf (
47- " name" to client.name,
48- " revenue " to allAssignments
49- .filter{ it.client == client}
48+ .map { client ->
49+ AggregationClient (
50+ name = client.name,
51+ revenueGross = allAssignments
52+ .filter { it.client == client }
5053 .toMapWorkingDay(from, to).values
5154 .flatten()
5255 .fold(BigDecimal .ZERO ) { acc, cur -> acc + cur.revenuePerDay() }
@@ -56,101 +59,108 @@ class AggregationService(
5659
5760 @Transactional
5861 fun
59- totalPerPerson (from : LocalDate , to : LocalDate ): List <Map < String , Any > > {
60- val all = fetchAll (from, to)
62+ totalPerPerson (from : LocalDate , to : LocalDate ): List <AggregationPerson > {
63+ val all = fetchAllData (from, to)
6164 val totalWorkDays = countWorkDaysInPeriod(from, to)
6265 return all.allPersons()
6366 .sortedBy { it.lastname }
6467 .map { person ->
65- mapOf (
66- " name" to " ${person.firstname} ${person.lastname} " ,
67- " type " to all.contract
68+ AggregationPerson (
69+ name = " ${person.firstname} ${person.lastname} " ,
70+ contractTypes = all.contract
6871 .filter { it.person == person }
69- .map { it::class .simpleName }
70- .toSet()
71- .joinToString(" ," ),
72- " sickDays" to all.sickDay.filter { it.person == person }.totalHoursInPeriod(from, to),
73- " workDays" to all.workDay.filter { it.assignment.person == person }.totalHoursInPeriod(from, to),
74- " assignment" to all.assignment
72+ .mapNotNull { it::class .simpleName }
73+ .toSet(),
74+ sickDays = all.sickDay.filter { it.person == person }.totalHoursInPeriod(from, to),
75+ workDays = all.workDay.filter { it.assignment.person == person }.totalHoursInPeriod(from, to),
76+ assignment = all.assignment
7577 .filter { it.person == person }
7678 .toMapWorkingDay(from, to).values
7779 .flatten()
7880 .fold(0 ) { acc, cur -> acc + cur.hoursPerWeek }
7981 .div(5 ),
80- " event" to all.event
82+ event = all.event
8183 .filter { it.persons.isEmpty() || it.persons.contains(person) }
8284 .fold(0 ) { acc, cur -> acc + cur.hours },
83- " total" to all.contract
85+ total = all.contract
8486 .filter { it.person == person }
8587 .map { it.totalHoursPerWeek() }
8688 .sum()
8789 .let { countWorkDaysInPeriod(from, to) * 8 * it / 40 },
88- " holiDayUsed" to all.holiDay.filter { it.person == person }.totalHoursInPeriod(from, to),
89- " holiDayBalance" to all.contract
90+ holiDayUsed = all.holiDay.filter { it.person == person }.totalHoursInPeriod(from, to),
91+ holiDayBalance = all.contract
9092 .filter { it.person == person }
9193 .filterIsInstance(ContractInternal ::class .java)
9294 .mapWorkingDay(from, to)
93- .map { BigDecimal (it.hoursPerWeek * 24 * 8 ) }
95+ .map { BigDecimal (it.hoursPerWeek * 24 * 8 ) }
9496 .sum()
95- .divide(BigDecimal (totalWorkDays * 40 ),10 , RoundingMode .HALF_UP ),
96- " revenue" to all.workDay
97+ .divide(BigDecimal (totalWorkDays * 40 ), 10 , RoundingMode .HALF_UP ),
98+ revenue = all.workDay
9799 .filter { it.assignment.person == person }
98100 .sumAmount()
99101 )
100102 }
101103 }
102104
103105 @Transactional
104- fun totalPerMonth (from : LocalDate , to : LocalDate ): List <Map < String , Any > > {
106+ fun totalPerMonth (from : LocalDate , to : LocalDate ): List <AggregationMonth > {
105107
106- val all = fetchAll (from, to)
108+ val all = fetchAllData (from, to)
107109 val months = (0 .. ChronoUnit .MONTHS .between(from, to))
108110 .map { from.plusMonths(it) }
109111 .map { YearMonth .from(it) }
110112 return months
111113 .map { yearMonth ->
112- mapOf (
113- " yearMonth" to yearMonth.toString(),
114- " countContractInternal" to all.contract
114+ AggregationMonth (
115+ yearMonth = yearMonth.toString(),
116+ countContractInternal = all.contract
115117 .filterIsInstance(ContractInternal ::class .java)
116118 .map { it.toDateRangeInPeriod(yearMonth) }
117119 .filter { it.isNotEmpty() }
118120 .count(),
119- " forecastRevenueGross" to all.assignment
121+ forecastRevenueGross = all.assignment
120122 .mapWorkingDay(yearMonth)
121123 .sumAmount(yearMonth),
122- " forecastRevenueNet" to all.assignment
124+ forecastRevenueNet = all.assignment
123125 .mapWorkingDay(yearMonth)
124126 .sumAmount(yearMonth)
125127 .multiply(netRevenueFactor(from, to)),
126- " actualRevenue" to all.workDay
128+ forecastHoursGross = all.assignment
129+ .mapWorkingDay(yearMonth)
130+ .sumAssignmentHoursPerWeek()
131+ .divide(yearMonth.countWorkDaysInMonth().times(5 ).toBigDecimal(), 10 , RoundingMode .HALF_UP ),
132+ actualRevenue = all.workDay
127133 .map { it.totalRevenueInPeriod(yearMonth) }
128134 .sum(),
129- " actualCostContractInternal" to all.contract
135+ actualHours = all.workDay
136+ .map { it.totalHoursInPeriod(yearMonth) }
137+ .sum()
138+ .divide(yearMonth.countWorkDaysInMonth().toBigDecimal(), 10 , RoundingMode .HALF_UP ),
139+ actualCostContractInternal = all.contract
130140 .filterIsInstance(ContractInternal ::class .java)
131141 .map { it.totalCostInPeriod(yearMonth) }
132142 .sum(),
133- " actualCostContractExternal" to yearMonth.toDateRange()
143+ actualCostContractExternal = yearMonth.toDateRange()
134144 .flatMap { date ->
135145 cartesianProducts(all.contract.filterIsInstance(ContractExternal ::class .java), all.workDay)
136146 .filter { (contract, workDay) -> contract.person == workDay.assignment.person }
137147 .filter { (contract, workDay) -> contract.inRange(date) && workDay.inRange(date) }
138148 .map { (contract, workDay) -> contract.hourlyRate.toBigDecimal() * workDay.hoursPerDay().getValue(date) }
139149 }
140150 .sum(),
141- " actualCostContractManagement" to all.contract
151+ actualCostContractManagement = all.contract
142152 .filterIsInstance(ContractManagement ::class .java)
143153 .map { it.totalCostInPeriod(yearMonth) }
144154 .sum(),
145- " actualCostContractService" to all.contract
155+ actualCostContractService = all.contract
146156 .filterIsInstance(ContractServiceModel ::class .java)
147157 .map { it.totalCostInPeriod(yearMonth) }
148158 .sum()
149159 )
150160 }
151161 }
152162
153- data class All (
163+ data class AllData (
154164 val sickDay : List <SickDay >,
155165 val holiDay : List <HoliDay >,
156166 val workDay : List <WorkDay >,
@@ -175,7 +185,7 @@ class AggregationService(
175185 .fold(0.0 ) { acc, cur -> acc + cur.hoursPerWeek / 5 }
176186 .pow(countWorkDaysInPeriod(from, to))
177187
178- private fun All .allPersons (): Set <Person > {
188+ private fun AllData .allPersons (): Set <Person > {
179189 return (this .assignment.map { it.person } +
180190 this .contract.map { it.person } +
181191 this .sickDay.map { it.person } +
@@ -185,14 +195,14 @@ class AggregationService(
185195 .toSet()
186196 }
187197
188- private fun fetchAll (from : LocalDate , to : LocalDate ): All {
198+ private fun fetchAllData (from : LocalDate , to : LocalDate ): AllData {
189199 val activeWorkDay = workDayService.findAllActive(from, to)
190200 val activeHoliDay = holiDayService.findAllActive(from, to)
191201 val activeSickDay = sickDayService.findAllActive(from, to)
192202 val activeAssignment = assignmentService.findAllActive(from, to)
193203 val activeContract = contractService.findAllActive(from, to)
194204 val activeEvent = eventService.findAllActive(from, to)
195- return All (
205+ return AllData (
196206 activeSickDay,
197207 activeHoliDay,
198208 activeWorkDay,
@@ -303,6 +313,14 @@ private fun <T : Period> List<T>.mapWorkingDay(yearMonth: YearMonth) = yearMonth
303313private fun <T : Period > Iterable<T>.sumAmount (yearMonth : YearMonth ) = this
304314 .fold(BigDecimal .ZERO ) { acc, cur -> acc + cur.amountPerWorkingDay(yearMonth) }
305315
316+ private fun Iterable<WorkDay>.sumWorkDayHoursPerWeek () = this
317+ .fold(BigDecimal .ZERO ) { acc, cur -> acc + cur.hours.toBigDecimal() }
318+
319+ private fun Iterable<Assignment>.sumAssignmentHoursPerWeek () = this
320+ .fold(BigDecimal .ZERO ) { acc, cur -> acc + cur.hoursPerWeek.toBigDecimal() }
321+
322+
323+
306324private fun Iterable<WorkDay>.sumAmount () = this
307325 .fold(BigDecimal .ZERO ) { acc, cur -> acc + (cur.hours * cur.assignment.hourlyRate).toBigDecimal() }
308326
@@ -339,6 +357,9 @@ fun WorkDay.totalRevenueInPeriod(period: Period): BigDecimal = this
339357fun WorkDay.totalRevenueInPeriod (yearMonth : YearMonth ): BigDecimal = this
340358 .totalRevenueInPeriod(yearMonth.toPeriod())
341359
360+ fun WorkDay.totalHoursInPeriod (yearMonth : YearMonth ): BigDecimal = this
361+ .totalHoursInPeriod(yearMonth.toPeriod())
362+
342363fun ContractInternal.totalCostInPeriod (yearMonth : YearMonth ): BigDecimal = this
343364 .toDateRangeInPeriod(yearMonth)
344365 .map { this .monthlySalary.toBigDecimal() }
0 commit comments