Procházet zdrojové kódy

update cash flow report

tags/Baseline_30082024_BACKEND_UAT
cyril.tsui před 1 rokem
rodič
revize
7562edd36d
1 změnil soubory, kde provedl 125 přidání a 74 odebrání
  1. +125
    -74
      src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt

+ 125
- 74
src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt Zobrazit soubor

@@ -855,6 +855,46 @@ open class ReportService(
combinedResults.forEach { result: String ->

if (groupedInvoices.containsKey(result)) {
if (dateType == "Date") {
groupedInvoices[result]!!.forEachIndexed { _, invoice ->
sheet.createRow(rowIndex++).apply {
createCell(0).apply {
setCellValue(result)
}

createCell(1).apply {
setCellValue(0.0)
cellStyle.dataFormat = accountingStyle
}

createCell(2).apply {
setCellValue(invoice["paidAmount"] as Double? ?: 0.0)
cellStyle.dataFormat = accountingStyle
}

createCell(3).apply {
val lastRow = rowIndex - 1
if (lastRow == 16) {
cellFormula =
"C{currentRow}-B{currentRow}".replace("{currentRow}", rowIndex.toString())
} else {
cellFormula =
"IF(B{currentRow}>0,D{lastRow}-B{currentRow},D{lastRow}+C{currentRow})".replace(
"{currentRow}",
rowIndex.toString()
).replace("{lastRow}", lastRow.toString())
}
cellStyle.dataFormat = accountingStyle
}

createCell(4)?.apply {
setCellValue(
"Invoice Receipt: " + (invoice["invoiceNo"] as String? ?: "N/A").toString()
)
}
}
}
} else {
// groupedInvoices[result]!!.forEachIndexed { _, invoice ->
sheet.createRow(rowIndex++).apply {
createCell(0).apply {
@@ -888,9 +928,16 @@ open class ReportService(

createCell(4)?.apply {
// setCellValue(invoice["description"].toString())
setCellValue("Invoice Receipt: " + (groupedInvoices[result]?.map { it["invoiceNo"] }?.joinToString() ?: "N/A").toString())
val invoiceNos = groupedInvoices[result]?.map { it["invoiceNo"] }
if (invoiceNos?.size != null && invoiceNos.size > 1) {
// setCellValue("Invoice Receipt: " + (groupedInvoices[result]?.map { it["invoiceNo"] }?.joinToString() ?: "N/A").toString())
setCellValue("Multiple Invoices")
} else {
setCellValue("Invoice Receipt: " + (invoiceNos?.joinToString() ?: "N/A").toString())
}
}
// }
}
}
}

@@ -1353,7 +1400,7 @@ open class ReportService(
for (i in 0 until rowSize) {
tempCell = sheet.getRow(8 + i).createCell(columnIndex + index)
tempCell.setCellValue(0.0)
if ( 8+i in holidayIndexList) {
if (8 + i in holidayIndexList) {
tempCell.cellStyle = fillOrange
}
tempCell.cellStyle.dataFormat = accountingStyle
@@ -1365,7 +1412,7 @@ open class ReportService(
dayInt = temp[index]["date"].toString().toInt()
tempCell = sheet.getRow(dayInt.plus(7)).createCell(columnIndex)
tempCell.setCellValue((temp[index]["normalConsumed"] as Double) + (temp[index]["otConsumed"] as Double))
if ( dayInt.plus(7) in holidayIndexList) {
if (dayInt.plus(7) in holidayIndexList) {
tempCell.cellStyle = fillOrange
tempCell.cellStyle.dataFormat = accountingStyle
}
@@ -1377,7 +1424,7 @@ open class ReportService(
for (i in 0 until rowSize) {
tempCell = sheet.getRow(8 + i).createCell(columnIndex)
tempCell.setCellValue(0.0)
if ( 8+i in holidayIndexList) {
if (8 + i in holidayIndexList) {
tempCell.cellStyle = fillOrange

}
@@ -1388,7 +1435,7 @@ open class ReportService(
dayInt = leave["recordDate"].toString().toInt()
tempCell = sheet.getRow(dayInt.plus(7)).createCell(columnIndex)
tempCell.setCellValue(leave["leaveHours"] as Double)
if ( dayInt.plus(7) in holidayIndexList) {
if (dayInt.plus(7) in holidayIndexList) {
tempCell.cellStyle = fillOrange

}
@@ -1420,7 +1467,7 @@ open class ReportService(
tempCell = sheet.getRow(rowIndex).createCell(columnIndex)
tempCell.cellFormula =
"SUM(${getColumnAlphabet(2)}${rowIndex + 1}:${getColumnAlphabet(columnIndex - 2)}${rowIndex + 1})" // should columnIndex - 2
if ( rowIndex in holidayIndexList) {
if (rowIndex in holidayIndexList) {
tempCell.cellStyle = fillOrange

}
@@ -1495,21 +1542,21 @@ open class ReportService(
}

val cell2 = getCell(2) ?: createCell(2)
cell2.cellFormula = "(B{currentRow}+D{currentRow})-1".replace("{currentRow}", (rowIndex+1).toString())
cell2.cellFormula = "(B{currentRow}+D{currentRow})-1".replace("{currentRow}", (rowIndex + 1).toString())
CellUtil.setAlignment(cell2, HorizontalAlignment.CENTER)
cell2.cellStyle.dataFormat = defaultStyle
// getCell(2).cellStyle.dataFormat = accountingStyle

val cell3 = getCell(3)?:createCell(3)
val cell3 = getCell(3) ?: createCell(3)
cell3.setCellValue(salary.increment.toDouble())
cell3.cellStyle = fillOrange
cell3.cellStyle.dataFormat = defaultStyle
CellUtil.setAlignment(cell3, HorizontalAlignment.CENTER)


val cell4 = getCell(4)?:createCell(4)
val cell4 = getCell(4) ?: createCell(4)
cell4.cellFormula =
"(((C{currentRow}+B{currentRow})/2)/20)/8".replace("{currentRow}", (rowIndex+1).toString())
"(((C{currentRow}+B{currentRow})/2)/20)/8".replace("{currentRow}", (rowIndex + 1).toString())
// getCell(4).cellStyle.dataFormat = accountingStyle
cell4.cellStyle.dataFormat = accountingStyle
CellUtil.setAlignment(cell4, HorizontalAlignment.CENTER)
@@ -1979,52 +2026,53 @@ open class ReportService(
}

open fun getProjectResourceOverconsumptionReport(args: Map<String, Any>): List<Map<String, Any>> {
val sql = StringBuilder("with teamNormalConsumed as ("
+ " SELECT"
+ " t.projectId,"
+ " p.teamLead,"
+ " sum(t.normalConsumed) as normalConsumed,"
+ " sum(t.otConsumed) as otConsumed,"
+ " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) as totalConsumed,"
+ " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) * sal.hourlyRate as totalBudget"
+ " from timesheet t"
+ " left join project p on p.id = t.projectId"
+ " left join staff s on s.id = p.teamLead"
+ " left join salary sal on sal.salaryPoint = s.salaryId"
+ " group by p.teamLead, t.projectId, sal.hourlyRate"
+ " )"
+ " SELECT"
+ " p.id,"
+ " p.code,"
+ " p.name,"
+ " t.code,"
+ " concat(c.code, ' - ',c.name) as client,"
+ " COALESCE(concat(ss.code, ' - ', ss.name), 'N/A') as subsidiary,"
+ " p.expectedTotalFee * 0.8 as plannedBudget,"
+ " COALESCE(tns.totalBudget, 0) as actualConsumedBudget,"
+ " tns.totalConsumed,"
+ " COALESCE(p.totalManhour, 0) as plannedManhour,"
+ " COALESCE(tns.totalConsumed, 0) as actualConsumedManhour,"
+ " (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) as budgetConsumptionRate,"
+ " (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) as manhourConsumptionRate,"
+ " CASE"
+ " when (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= :lowerLimit and (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) <= 1"
+ " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= :lowerLimit and (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) <= 1"
+ " then 'Potential Overconsumption'"
+ " when (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= 1"
+ " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= 1"
+ " then 'Overconsumption'"
+ " else 'Within Budget'"
+ " END as status"
+ " from project p"
+ " left join staff s on s.id = p.teamLead"
+ " left join team t on t.id = s.teamId"
+ " left join customer c on c.id = p.customerId"
+ " LEFT JOIN subsidiary ss on p.customerSubsidiaryId = ss.id"
+ " LEFT JOIN salary sa ON s.salaryId = sa.salaryPoint"
+ " left join teamNormalConsumed tns on tns.projectId = p.id"
+ " WHERE p.deleted = false "
+ " and p.status = 'On-going' "
val sql = StringBuilder(
"with teamNormalConsumed as ("
+ " SELECT"
+ " t.projectId,"
+ " p.teamLead,"
+ " sum(t.normalConsumed) as normalConsumed,"
+ " sum(t.otConsumed) as otConsumed,"
+ " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) as totalConsumed,"
+ " sum(t.normalConsumed + COALESCE(t.otConsumed, 0)) * sal.hourlyRate as totalBudget"
+ " from timesheet t"
+ " left join project p on p.id = t.projectId"
+ " left join staff s on s.id = p.teamLead"
+ " left join salary sal on sal.salaryPoint = s.salaryId"
+ " group by p.teamLead, t.projectId, sal.hourlyRate"
+ " )"
+ " SELECT"
+ " p.id,"
+ " p.code,"
+ " p.name,"
+ " t.code,"
+ " concat(c.code, ' - ',c.name) as client,"
+ " COALESCE(concat(ss.code, ' - ', ss.name), 'N/A') as subsidiary,"
+ " p.expectedTotalFee * 0.8 as plannedBudget,"
+ " COALESCE(tns.totalBudget, 0) as actualConsumedBudget,"
+ " tns.totalConsumed,"
+ " COALESCE(p.totalManhour, 0) as plannedManhour,"
+ " COALESCE(tns.totalConsumed, 0) as actualConsumedManhour,"
+ " (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) as budgetConsumptionRate,"
+ " (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) as manhourConsumptionRate,"
+ " CASE"
+ " when (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= :lowerLimit and (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) <= 1"
+ " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= :lowerLimit and (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) <= 1"
+ " then 'Potential Overconsumption'"
+ " when (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= 1"
+ " or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= 1"
+ " then 'Overconsumption'"
+ " else 'Within Budget'"
+ " END as status"
+ " from project p"
+ " left join staff s on s.id = p.teamLead"
+ " left join team t on t.id = s.teamId"
+ " left join customer c on c.id = p.customerId"
+ " LEFT JOIN subsidiary ss on p.customerSubsidiaryId = ss.id"
+ " LEFT JOIN salary sa ON s.salaryId = sa.salaryPoint"
+ " left join teamNormalConsumed tns on tns.projectId = p.id"
+ " WHERE p.deleted = false "
+ " and p.status = 'On-going' "
)
if (args != null) {
var statusFilter: String = ""
@@ -2041,6 +2089,7 @@ open class ReportService(
" and (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) <= 1 " +
" or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= :lowerLimit " +
" and (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) <= 1 "

"All" -> " and " +
" (COALESCE((tns.totalConsumed * sa.hourlyRate), 0) / p.expectedTotalFee) >= :lowerLimit " +
" or (COALESCE(tns.totalConsumed, 0) / COALESCE(p.totalManhour, 0)) >= :lowerLimit "
@@ -2105,17 +2154,17 @@ open class ReportService(
+ " order by g.code, s.name, cte_ts.recordDate"
)
val projectPlanStartEndMonth = projectRepository.findProjectPlanStartEndByIdAndDeletedFalse(projectId)
val compareStartMonth= YearMonth.parse(startMonth)
val compareEndMonth= YearMonth.parse(endMonth)
val compareStartMonth = YearMonth.parse(startMonth)
val compareEndMonth = YearMonth.parse(endMonth)
val actualStartMonth: YearMonth
(if (projectPlanStartEndMonth.actualStart == null){
(if (projectPlanStartEndMonth.actualStart == null) {
YearMonth.now().plusMonths(1)
}else{
} else {
YearMonth.from(projectPlanStartEndMonth.actualStart)
}).also { actualStartMonth = it }

val queryStartMonth = if(compareStartMonth.isAfter(actualStartMonth)) compareStartMonth else actualStartMonth
val queryEndMonth = if(compareEndMonth.isAfter(YearMonth.now())) YearMonth.now() else compareEndMonth
val queryStartMonth = if (compareStartMonth.isAfter(actualStartMonth)) compareStartMonth else actualStartMonth
val queryEndMonth = if (compareEndMonth.isAfter(YearMonth.now())) YearMonth.now() else compareEndMonth

val args = mapOf(
"projectId" to projectId,
@@ -2251,7 +2300,8 @@ open class ReportService(

val manhoursSpentList = getManhoursSpent(projectId, startMonth, endMonth)

val workbook: Workbook = createPandLReportWorkbook(PandL_REPORT, manhoursSpentList, startMonth, endMonth, projectId)
val workbook: Workbook =
createPandLReportWorkbook(PandL_REPORT, manhoursSpentList, startMonth, endMonth, projectId)

val outputStream: ByteArrayOutputStream = ByteArrayOutputStream()
workbook.write(outputStream)
@@ -2274,17 +2324,17 @@ open class ReportService(
val accountingStyle = workbook.createDataFormat().getFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)")

val projectPlanStartEndMonth = projectRepository.findProjectPlanStartEndByIdAndDeletedFalse(projectId)
val compareStartMonth= YearMonth.parse(startMonth)
val compareEndMonth= YearMonth.parse(endMonth)
val compareStartMonth = YearMonth.parse(startMonth)
val compareEndMonth = YearMonth.parse(endMonth)
val actualStartMonth: YearMonth
(if (projectPlanStartEndMonth.actualStart == null){
(if (projectPlanStartEndMonth.actualStart == null) {
YearMonth.now().plusMonths(1)
}else{
} else {
YearMonth.from(projectPlanStartEndMonth.actualStart)
}).also { actualStartMonth = it }

val queryStartMonth = if(compareStartMonth.isAfter(actualStartMonth)) compareStartMonth else actualStartMonth
val queryEndMonth = if(compareEndMonth.isAfter(YearMonth.now())) YearMonth.now() else compareEndMonth
val queryStartMonth = if (compareStartMonth.isAfter(actualStartMonth)) compareStartMonth else actualStartMonth
val queryEndMonth = if (compareEndMonth.isAfter(YearMonth.now())) YearMonth.now() else compareEndMonth

val monthFormat = DateTimeFormatter.ofPattern("MMM yyyy", Locale.ENGLISH)
val startDate = YearMonth.parse(queryStartMonth.toString(), DateTimeFormatter.ofPattern("yyyy-MM"))
@@ -2294,7 +2344,7 @@ open class ReportService(

val monthRange: MutableList<Map<String, Any>> = ArrayList()
var currentDate = startDate
if (currentDate == endDate){
if (currentDate == endDate) {
monthRange.add(
mapOf(
"display" to YearMonth.of(currentDate.year, currentDate.month).format(monthFormat),
@@ -2575,7 +2625,7 @@ open class ReportService(
}
// CellUtil.setCellStyleProperty(panlCellTitle, "borderBottom", BorderStyle.DOUBLE)
// CellUtil.setCellStyleProperty(panlCell, "borderBottom", BorderStyle.DOUBLE)
val profitAndLossRowNum = rowNum+1
val profitAndLossRowNum = rowNum + 1

rowNum += 1
val uninvoicedAmountRow: Row = sheet.getRow(rowNum) ?: sheet.createRow(rowNum)
@@ -2585,7 +2635,7 @@ open class ReportService(
}
val uninvoicedAmountCell = uninvoicedAmountRow.getCell(1) ?: uninvoicedAmountRow.createCell(1)
uninvoicedAmountCell.apply {
setCellValue(if ((info.getValue("expectedTotalFee") as Double) < 0.0 ) 0.0 else info.getValue("expectedTotalFee") as Double)
setCellValue(if ((info.getValue("expectedTotalFee") as Double) < 0.0) 0.0 else info.getValue("expectedTotalFee") as Double)
cellStyle.dataFormat = accountingStyle
}

@@ -2597,7 +2647,7 @@ open class ReportService(
}
val projectedPnLCell = projectedPnLRow.getCell(1) ?: projectedPnLRow.createCell(1)
projectedPnLCell.apply {
cellFormula = "B${profitAndLossRowNum}+B${profitAndLossRowNum+1}"
cellFormula = "B${profitAndLossRowNum}+B${profitAndLossRowNum + 1}"
cellStyle.dataFormat = accountingStyle
}

@@ -3063,7 +3113,8 @@ open class ReportService(
}

createCell(columnIndex++).apply {
val cellValue = grade.name.trim().substring(0,1) + grade.name.trim().substring(grade.name.length - 1) + " - Cost Adjusted by Salary Point"
val cellValue = grade.name.trim().substring(0, 1) + grade.name.trim()
.substring(grade.name.length - 1) + " - Cost Adjusted by Salary Point"
setCellValue(cellValue)
val cloneStyle = workbook.createCellStyle()
cloneStyle.cloneStyleFrom(boldFontWithBorderStyle)


Načítá se…
Zrušit
Uložit