From 2c4e77c7d7cd4088f4a2f5a87b3e50e6b8f23ad9 Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Thu, 4 Jul 2024 14:01:47 +0800 Subject: [PATCH] update cross team charge report --- .../modules/report/service/ReportService.kt | 247 ++++++++++-------- .../report/Cross Team Charge Report.xlsx | Bin 18610 -> 18521 bytes 2 files changed, 142 insertions(+), 105 deletions(-) diff --git a/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt b/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt index de32af4..6c492fd 100644 --- a/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt +++ b/src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt @@ -2766,147 +2766,184 @@ open class ReportService( setCellValue(convertReportMonth) } - if (timesheets.isNotEmpty()) { - val combinedTeamCodeColNumber = grades.size - val sortedGrades = grades.sortedBy { it.id } - val sortedTeams = teams.sortedBy { it.id } - - val groupedTimesheets = timesheets - .filter { it.project?.teamLead?.team?.id != it.staff?.team?.id } - .groupBy { timesheetEntry -> - Triple( - timesheetEntry.project?.teamLead?.team?.id, - timesheetEntry.staff?.team?.id, - timesheetEntry.staff?.grade?.id - ) - } - .mapValues { (_, timesheetEntries) -> - timesheetEntries.map { timesheet -> - if (timesheet.normalConsumed != null) { - timesheet.normalConsumed!!.plus(timesheet.otConsumed ?: 0.0) - } else if (timesheet.otConsumed != null) { - timesheet.otConsumed!!.plus(timesheet.normalConsumed ?: 0.0) - } else { - 0.0 +// if (timesheets.isNotEmpty()) { + val combinedTeamCodeColNumber = grades.size + val sortedGrades = grades.sortedBy { it.id } + val sortedTeams = teams.sortedBy { it.id } + + val groupedTimesheets = timesheets + .filter { it.project?.teamLead?.team?.id != it.staff?.team?.id } + .groupBy { timesheetEntry -> + Triple( + timesheetEntry.project?.teamLead?.team?.id, + timesheetEntry.staff?.team?.id, + timesheetEntry.staff?.grade?.id + ) + } + .mapValues { (_, timesheetEntries) -> + timesheetEntries.map { timesheet -> + if (timesheet.normalConsumed != null) { + mutableMapOf().apply { + this["manHour"] = timesheet.normalConsumed!!.plus(timesheet.otConsumed ?: 0.0) + this["salary"] = timesheet.normalConsumed!!.plus(timesheet.otConsumed ?: 0.0) + .times(timesheet.staff!!.salary.hourlyRate.toDouble()) + } + } else if (timesheet.otConsumed != null) { + mutableMapOf().apply { + this["manHour"] = timesheet.otConsumed!!.plus(timesheet.normalConsumed ?: 0.0) + this["salary"] = timesheet.otConsumed!!.plus(timesheet.normalConsumed ?: 0.0) + .times(timesheet.staff!!.salary.hourlyRate.toDouble()) + } + } else { + mutableMapOf().apply { + this["manHour"] = 0.0 + this["salary"] = 0.0 } } } + } - if (sortedTeams.isNotEmpty() && sortedTeams.size > 1) { - rowIndex = 3 - sortedTeams.forEach { team: Team -> + if (sortedTeams.isNotEmpty() && sortedTeams.size > 1) { + rowIndex = 3 + sortedTeams.forEach { team: Team -> - // Team - sheet.createRow(rowIndex++).apply { - createCell(0).apply { - setCellValue("Team to be charged:") - cellStyle = boldFontWithBorderStyle.apply { - alignment = HorizontalAlignment.LEFT - } - } + // Team + sheet.createRow(rowIndex++).apply { + createCell(0).apply { + setCellValue("Team to be charged:") + cellStyle = boldFontWithBorderStyle + CellUtil.setAlignment(this, HorizontalAlignment.LEFT) + } - val rangeAddress = CellRangeAddress(this.rowNum, this.rowNum, 1, 1 + combinedTeamCodeColNumber) - sheet.addMergedRegion(rangeAddress) - RegionUtil.setBorderTop(BorderStyle.THIN, rangeAddress, sheet) - RegionUtil.setBorderLeft(BorderStyle.THIN, rangeAddress, sheet) - RegionUtil.setBorderRight(BorderStyle.THIN, rangeAddress, sheet) - RegionUtil.setBorderBottom(BorderStyle.THIN, rangeAddress, sheet) + val rangeAddress = CellRangeAddress(this.rowNum, this.rowNum, 1, 2 + combinedTeamCodeColNumber) + sheet.addMergedRegion(rangeAddress) + RegionUtil.setBorderTop(BorderStyle.THIN, rangeAddress, sheet) + RegionUtil.setBorderLeft(BorderStyle.THIN, rangeAddress, sheet) + RegionUtil.setBorderRight(BorderStyle.THIN, rangeAddress, sheet) + RegionUtil.setBorderBottom(BorderStyle.THIN, rangeAddress, sheet) - createCell(1).apply { - setCellValue(team.code) - cellStyle = normalFontWithBorderStyle.apply { - alignment = HorizontalAlignment.CENTER - } - } + createCell(1).apply { + setCellValue(team.code) + cellStyle = normalFontWithBorderStyle + CellUtil.setAlignment(this, HorizontalAlignment.CENTER) + } + + } + // Grades + sheet.createRow(rowIndex++).apply { + columnIndex = 0 + createCell(columnIndex++).apply { + setCellValue("") + cellStyle = boldFontWithBorderStyle } - // Grades - sheet.createRow(rowIndex++).apply { - columnIndex = 0 + + sortedGrades.forEach { grade: Grade -> createCell(columnIndex++).apply { - setCellValue("") + setCellValue(grade.name) cellStyle = boldFontWithBorderStyle + CellUtil.setAlignment(this, HorizontalAlignment.CENTER) } + } + createCell(columnIndex++).apply { + setCellValue("Total Manhour by Team") + cellStyle = boldFontWithBorderStyle + } - sortedGrades.forEach { grade: Grade -> + createCell(columnIndex).apply { + setCellValue("Total Cost Adjusted by Salary Point by Team") + cellStyle = boldFontWithBorderStyle + } + } + + // Team + Manhour + val startRow = rowIndex + var endRow = rowIndex + sortedTeams.forEach { chargedTeam: Team -> + if (team.id != chargedTeam.id) { + endRow++ + sheet.createRow(rowIndex++).apply { + columnIndex = 0 createCell(columnIndex++).apply { - setCellValue(grade.name) - cellStyle = boldFontWithBorderStyle.apply { - alignment = HorizontalAlignment.CENTER - } + setCellValue(chargedTeam.code) + cellStyle = normalFontWithBorderStyle + CellUtil.setAlignment(this, HorizontalAlignment.CENTER) } - } - createCell(columnIndex).apply { - setCellValue("Total Manhour by Team") - cellStyle = boldFontWithBorderStyle - } - } - - // Team + Manhour - val startRow = rowIndex - var endRow = rowIndex - sortedTeams.forEach { chargedTeam: Team -> - if (team.id != chargedTeam.id) { - endRow++ - sheet.createRow(rowIndex++).apply { - columnIndex = 0 + var totalSalary = 0.0 + sortedGrades.forEach { grade: Grade -> createCell(columnIndex++).apply { - setCellValue(chargedTeam.code) - cellStyle = normalFontWithBorderStyle + setCellValue( + groupedTimesheets[Triple( + team.id, + chargedTeam.id, + grade.id + )]?.sumOf { it.getValue("manHour") } ?: 0.0) + + totalSalary += groupedTimesheets[Triple( + team.id, + chargedTeam.id, + grade.id + )]?.sumOf { it.getValue("salary") } ?: 0.0 + + cellStyle = normalFontWithBorderStyle.apply { + dataFormat = accountingStyle + } } + } - sortedGrades.forEach { grade: Grade -> - createCell(columnIndex++).apply { - setCellValue( - groupedTimesheets[Triple(team.id, chargedTeam.id, grade.id)]?.sum() ?: 0.0 - ) - cellStyle = normalFontWithBorderStyle.apply { - dataFormat = accountingStyle - } - } + createCell(columnIndex++).apply { + val lastCellLetter = CellReference.convertNumToColString(this.columnIndex - 1) + cellFormula = "sum(B${this.rowIndex + 1}:${lastCellLetter}${this.rowIndex + 1})" + cellStyle = boldFontWithBorderStyle.apply { + dataFormat = accountingStyle } + } - createCell(columnIndex).apply { - val lastCellLetter = CellReference.convertNumToColString(this.columnIndex - 1) - cellFormula = "sum(B${this.rowIndex + 1}:${lastCellLetter}${this.rowIndex + 1})" - cellStyle = boldFontWithBorderStyle.apply { - dataFormat = accountingStyle - } + createCell(columnIndex).apply { + setCellValue(totalSalary) + cellStyle = boldFontWithBorderStyle.apply { + dataFormat = accountingStyle } } } } + } - // Total Manhour by grade - sheet.createRow(rowIndex).apply { - columnIndex = 0 - createCell(columnIndex++).apply { - setCellValue("Total Manhour by Grade") - cellStyle = boldFontWithBorderStyle - } + // Total Manhour by grade + sheet.createRow(rowIndex).apply { + columnIndex = 0 + createCell(columnIndex++).apply { + setCellValue("Total Manhour by Grade") + cellStyle = boldFontWithBorderStyle + } - sortedGrades.forEach { grade: Grade -> - createCell(columnIndex++).apply { - val currentCellLetter = CellReference.convertNumToColString(this.columnIndex) - cellFormula = "sum(${currentCellLetter}${startRow}:${currentCellLetter}${endRow})" - cellStyle = normalFontWithBorderStyle.apply { - dataFormat = accountingStyle - } + sortedGrades.forEach { grade: Grade -> + createCell(columnIndex++).apply { + val currentCellLetter = CellReference.convertNumToColString(this.columnIndex) + cellFormula = "sum(${currentCellLetter}${startRow}:${currentCellLetter}${endRow})" + cellStyle = normalFontWithBorderStyle.apply { + dataFormat = accountingStyle } } + } - createCell(columnIndex).apply { - setCellValue("") - cellStyle = boldFontWithBorderStyle - } + createCell(columnIndex++).apply { + setCellValue("") + cellStyle = boldFontWithBorderStyle + } + + createCell(columnIndex).apply { + setCellValue("") + cellStyle = boldFontWithBorderStyle } - rowIndex += 2 } + rowIndex += 2 } } +// } return workbook } diff --git a/src/main/resources/templates/report/Cross Team Charge Report.xlsx b/src/main/resources/templates/report/Cross Team Charge Report.xlsx index 26e201fe936564e94d206545a128e17f0ac0eab3..e3c005a23f087aa5389b235725ec40af2280a760 100644 GIT binary patch delta 5760 zcmZ8lbx;)E{#{BMmTm-gSyDi{dzVI60qF)oVktp#Y3W)@KsuBT0YPd(=~C%hN?=I= z0YT#DdvE4_=lAX(ckayRGiPp`J7>;mOvRZ`!KvTBha4y!^~%Eo02qk@07?J=@XA%# z58>rvi$J&ty>fG{Hnc#jOVb8hIp0NOR4l(1$8g4KYec5J)pm#sb@Ssc9R`;h>#bKG z&`vtt{;?#){lJzuHx9ENuo~E22|OG-t8gE|dm`m25A0L`JTi#Ys!2UvT4Y2Ls3CyqcPG z_vjuB-dMI1&7LusS8CER^Vg@8CRhcF%_SQ#;*N5yC8Aj4TgfO?FX|um-E8RCzWTJQhXNZN|Le)@u6(u69b3ShuzI z)$pzyJJZD%Vd(#uOdaG~M2WUyYV0;TF}-{r_XLhB#p79oXg<`KQfyh(-e zV8}0L^1KL z$5pz!)tH`TJo9JQW=Njuyq0WDFG2tvKlTK@h9nrB>}PxXj=B?keK_cmswe%#f@OYE z^x*LUhnYW*{bEERpYe;ft-|NX=vwzA)<=F3lQVd;4QEBUbD%mYZCFEvZH*%T*E_iB zVn2BAo*nK6)+xU1>oYZ;#Y# zZR^)#Z{pVg?aPk29e(mMVY;|H-@sIYjgW}K0luc+L zXwTTJ0oGdlS-5xo6gw-7YLco%GQQq#LdG&sjm+ zMJ9Bmh?azB4j5XU?RuOkA~_)9W1%BdD{jU2wf({8m}r?vL{?*yg5I&6N8FnVL#b8M zm!a7su=Xs#7tQ12gW~DvF_xV`HQo&;yH!-L)Ls_x1*WDHEVZz^098(E&B3%P#c4d; z2>kZvHn|tb%yKMvbC3No66>6%+4a1P(Abx&dakd-!m%UGFxILmD4RPAD#|-Zz%V{XFm*<2JD1mE=k=es6AQ z!aJQHm42!B_o?n(r`x(=%s~TN7sXUd#3||`S0&Bu+tpNU~}66q;TU@AglwD)~z2tT~Za6{3Bvx~~B!KaWfnPg(CJZ)bP1g8vj-IRk}MU zn>3Zv{D#X^zi)ewmTOM7k5wlU~>3VEA?vBNnF6eJ;{4eN&If# zY)W3mx16eXe}&@iKa+Wi8A*f)5ZX%Zh{I;*=8PNxTjwgaP^tf{qNCYA*NaJ(K9yjl z80}Q6bumL!x8_7+tjI{fM6-)^q>Bf*#iu00>mD74_rxXOwIwx$xK!c{JMSEz(l2@) zjSl0(#a?+>OTY5^xxPAv=D}mkseUY)AH*Tu?>$2X0J zIYP{H7xd553Czd~@Vl^G3EjviS|sHe@MiKb)&ubZ_wJaum_|IT&)sty4|?ZY{v|;2 zyG>CoX{Gu!kYFbeMj?Wn6;iN_uT<|o4$}0HWG3H|;k!3KmbF%xJs=e!&$fOkI8hgG za!shmv%*6eAdB5eQ}X(=q_9&+f3Bs_L;jOLt{k7rWbZ&A#|j&X?9IcCBT zV6y#Y(ZXe$pc3-CU9ts$(7ipmr^4w0p4bZxNnhDleQ%ncDRUw_PFz-$uh_;{t*?JI zFP*8x2l~|Q1y7qHf!3sSb=dZX*~&{!{!jdHs`ZbWuVog5gP-Qg31te9R-U9tOFktZ ze2q~i@zY1=`|NEv5^6=;?>|N|K_DL_3*cj_~nSg=)ykKzrkR0xm ziH98`3U$Is4tcci3=CxMx5-@7@t?Gq0Np{C>nl{2F5>gf_pXSCOZEs^rnkf)dg%j8WpWoXE@Wlp8lcBV=m_h?RmOzkjs z0Jbiq@dFGIb^o|1{}^QAFqOwY7Rr4JVPYQ^&;BA3??68w=;Efb7lwfvC%5(nXe-u! z#dRL)9@2Ca)=b)bP6OrCHJ!_u#v!#>~%k4PdNy5M&{m!TN`ZaIo-Rn6ZWL+T~l zr~g{(`IgSfGcOXqB|fNiS|VfNb7-w# zT+XcPv!~>S6D1Z$ClfK0(r^?1k_O z(096DJBvH1>KEADvNB^a6^ZCVfQM+F23W7B?AynAC$M z`#3&jT%msYz#*-dLuQ7hA%unwSuWHRt;O3Lom?B0g!N`qsp4nfHtKCnKcWihC2(|5 zGxVCs=82^dkz!~RPVx3F(WeC+>xyJ55Xb5g*~e1nxLn&M>F{)^)7XcL)uuAZ6E*|w zTl0fddY_|a{ok7tp4P}kfGb&~iU!-9yf(HVeR`R>tWq_Dk#&J096$c#Cr0k}E2yJp zK5~=0Eu}?Ex@+|@xAGPz%EeCgKZs*a40JL_ra&XVyHoW}PJRqFED|1@)0t_o77pHk zcN(3wZ`R2E5z!UlZ5F;_H}3uVEMKL(#~NaotE%_S^(g#h@wUa78UH5_C%y_eSN zStXKyVhIv^9Zr@JaOp@QL!Ijb#e580|Wl~m&xPR%^2Y8ms3CW8ah#`Iq-=a=g*(zk3!nr{Q(6+{1e$I9? zs>vIf@WjeYzr+(=bLaoQ0Blpe`H-S6frO->6dCl;k&K_r;f%Haeqbo1L*z0E5z}fl zEfsD5`|LK6xL$O5Z~j>W8{9Tx>L8I35j*i812Ml)zO3r}Jh&SpdVdi$R@X zr;vXY|HIzq_1`I`Y&Ac)SsxgcjOL+rz0{QC{+>>X3jV{WB1xihw$d`IgB+>L_-80F zA6}Sq0D^>)hf8{AG4y)zY;5zc@<6Lgoi~MGPMi9t%o2_N0*2}m-S?YM95v-?{3YJS zrlDGm%?n8&>V91AtzB5@2k(TPnNEK?$Tb>yQO0vBqLWPa#!g+GjwX$WA#^X>B&$pi zmhtF|eD9e}3~|Le@F5Pr>hNEt6*4{6B|v7LWm%ih<0Fcm{ zaYNc0Z(2n`G2O|olW{)PlIi!D%;|=I@ypGo*V#)B^Sg+Hod%M};dd$bK&^UfVEb)C z0a_OrzXAa#cGMXh6$d2lHqYr?7@ovs16P87Z%0w5y4R#Q-uiQ9Bg_rB^+56p{9%=L zf4eIE7Nu%3>AtJ^J&GOt22$G+QZ0-l)-tf`^=v;ht(Ggnxt6pc^h;I2tyoVNS(6?c z3)N}rVjd?%0+w&VAOZjYj}ZVM|BtQp_VIUh@cx&n9W^$KUxd+y2>((ddXQdfQ1xln z%M}q!ga3`&r*-mm57!7N@SV`OQ%CAk+$hx{om(xWvegxWdS_zi4b#xKg*}V;6&*|0 zv9F^tn6{*G=K@DKuLWn?I{0w#ssWzy6nXH zViB>xXA!*<6b;M>h35HgGL@ZXR+itAK`jIFM&V?L@JMy`DDF3v*gOtITB92L9dpji zV-V#)Cn%^c`mI13c%>uH$9^Q8do5i>6i3WL@sFkK)!L4x+{}lOZQ;3-v8M2!Fkn~U zC(RvF==IzD6E`JG#jI&}voQzXMHM7$ga=uZNl=HF0I&d65^%PfXAN`p!iAfot4TUWF;V)Ww*!80giSU^<%3 z+(zGg?j79L-rN#lLQ*CF-W}<}F3YHMXh5WQKWa_pbfFH-udn;lg5F@5+dM{)&E$uD zGBEwJB!;*Fkg!OBHKTmF`1q*YGt!n2I(9dcz{M4crMGT5&FHw4H*W{z zsL>1bSkzw0OAWuQ>w%|Pq9VBpPU>(I2i&JkdwuDenD#5@m))PxFCkrfD$DzgNVf*i zwB|!iP;uDjANN`Jz1}m2uPsh5(ap~GbBtOJ)-s;UhMK7U4EzZ^l^(HcbHtbDC`|;W zuTUXE!bER5(Uog3d80|=mv0RicR2j&A7$r?c|HKM&#}oqm8+w8L|<+QY$o>(tc@9! z0S6pWy6|7i%|VM}2*#JGefuQ%~vz*}Xa99a?(plPc!nOVW zZ~N*Um^ZDJ;?3oc4Xc8?8-o)ET#_yY3zyyU`Df91-;D(Sd^XBSOs$m$0c|J(^p>%n zUFLx+Tj4km6Xg8vNlQ|r$@^Dk3EIkQ#3UV1O<^NpIj_rWnw(WAzVV4g-LavnOnj2L zVz=#gy0?$g3!`3T^uEKrEh9i%r^D|)GbNd;Ill;Yq_r1FTE5TUBC$jHy0(OAVO7n+ zHn687lQO$VYP!aVxz`|Tb9ifYLdR62RuDgENvep=Kc1yoSHkZ@N|F!9lu2h%iPUMcfb$S zAiLkyG`a3)cOdfRFEtw#v!X5t76!G;c*%%Pl#jJFUuu4J={kEhD3-~Gj?-3&GZk@q zyNu!PDDU|8v$~4;Lx#1y#*^q1S*V7KOI*X62JahUbG0@PD{Puc>lBjETtt%61*U;5fvtrn^|Te48H%)&FTMQm3f7(~6j78k9>;E)WbBozT*?QymIY?Z9nZ`E#ygj{%?xNobppD$nqU{~N!eFzWg^ z6(}L-1J-{6oxic{U+wy59Fw8Q$eB?YFd*xHE$+krZR!A`I-%+~2ox?10{LGZ{0B>n z>)&DTzf}>H0;5B1^8iWzDTkp#U@EvPyeKs65zZ>A2gZs*@ROjVH285h_)#(9VAN|3 xVH{ditA+s%6h)>9V)-{sZ~y=+TmXRTAE3W06iQoD5r+{Ks|mVys`jta{{g?W!ae{1 delta 5825 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