Przeglądaj źródła

Merge branch 'master' of https://git.2fi-solutions.com/davidhui/TSMS-backend

# Conflicts:
#	src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt
#	src/main/resources/templates/report/AR01_Late Start Report v01.xlsx
tags/Baseline_30082024_BACKEND_UAT
leoho2fi 1 rok temu
rodzic
commit
d16f77bffb
28 zmienionych plików z 1418 dodań i 461 usunięć
  1. +386
    -2
      src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt
  2. +13
    -16
      src/main/java/com/ffii/tsms/modules/data/service/TeamService.kt
  3. +76
    -0
      src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt
  4. +22
    -1
      src/main/java/com/ffii/tsms/modules/data/web/TeamController.kt
  5. +5
    -5
      src/main/java/com/ffii/tsms/modules/data/web/models/NewStaffRequest.kt
  6. +2
    -1
      src/main/java/com/ffii/tsms/modules/data/web/models/NewTeamRequest.kt
  7. +6
    -1
      src/main/java/com/ffii/tsms/modules/project/entity/ProjectRepository.kt
  8. +1
    -0
      src/main/java/com/ffii/tsms/modules/project/entity/ProjectTaskRepository.kt
  9. +629
    -281
      src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt
  10. +48
    -8
      src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt
  11. +13
    -0
      src/main/java/com/ffii/tsms/modules/report/web/model/ReportRequest.kt
  12. +5
    -0
      src/main/java/com/ffii/tsms/modules/timesheet/entity/Timesheet.kt
  13. +3
    -1
      src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt
  14. +6
    -0
      src/main/java/com/ffii/tsms/modules/user/req/UpdateUserReq.java
  15. +0
    -33
      src/main/resources/db/changelog/changes/20240318_01_wayne/02_mock_team_leads.sql
  16. +0
    -112
      src/main/resources/db/changelog/changes/20240414_01_wayne/01_mock_staffs.sql
  17. +6
    -0
      src/main/resources/db/changelog/changes/20240525_01_wayne/01_timesheet_project.sql
  18. +123
    -0
      src/main/resources/db/changelog/changes/20240527_01_cyril/01_update_task.sql
  19. +74
    -0
      src/main/resources/db/changelog/changes/20240527_01_cyril/02_update_position.sql
  20. BIN
      src/main/resources/templates/report/AR02_Delay Report v02.xlsx
  21. BIN
      src/main/resources/templates/report/AR03_Resource Overconsumption.xlsx
  22. BIN
      src/main/resources/templates/report/AR04_Cost and Expense Report v02.xlsx
  23. BIN
      src/main/resources/templates/report/AR05_Project Completion Report.xlsx
  24. BIN
      src/main/resources/templates/report/AR06_Project Completion Report with Outstanding Accounts Receivable v02.xlsx
  25. BIN
      src/main/resources/templates/report/AR07_Project P&L Report v02.xlsx
  26. BIN
      src/main/resources/templates/report/AR08_Monthly Work Hours Analysis Report.xlsx
  27. BIN
      src/main/resources/templates/report/EX01_Financial Status Report.xlsx
  28. BIN
      src/main/resources/templates/report/EX02_Project Cash Flow Report.xlsx

+ 386
- 2
src/main/java/com/ffii/tsms/modules/data/service/DashboardService.kt Wyświetl plik

@@ -509,8 +509,8 @@ open class DashboardService(
+ " p.name as projectName,"
+ " t.code as team,"
+ " s.name as teamLead,"
+ " p.actualStart as startDate,"
+ " p.planEnd as targetEndDate,"
+ " date_format(p.actualStart, '%Y-%m-%d') as startDate,"
+ " date_format(p.planEnd, '%Y-%m-%d') as targetEndDate,"
+ " c.name as client,"
+ " coalesce(s2.name,'N/A') as subsidiary"
+ " from project p"
@@ -524,6 +524,390 @@ open class DashboardService(

return jdbcDao.queryForList(sql.toString(), args)
}
fun CashFlowMonthlyIncomeByMonth(args: Map<String, Any>): List<Map<String, Any>> {
val sql = StringBuilder("select"
+ " months.month as monthInvoice,"
+ " coalesce (invoice.invoiceMonth,'-') as invoiceMonth,"
+ " coalesce (invoice.income,0) as income,"
+ " SUM(COALESCE(invoice.income, 0)) OVER (ORDER BY months.month) AS cumulativeIncome"
+ " FROM ("
+ " SELECT 01 AS month"
+ " UNION"
+ " SELECT 02"
+ " UNION"
+ " SELECT 03"
+ " UNION"
+ " SELECT 04"
+ " UNION"
+ " SELECT 05"
+ " UNION"
+ " SELECT 06"
+ " UNION"
+ " SELECT 07"
+ " UNION"
+ " SELECT 08"
+ " UNION"
+ " SELECT 09"
+ " UNION"
+ " SELECT 10"
+ " UNION"
+ " SELECT 11"
+ " union"
+ " select 12"
+ " ) AS months"
+ " left join("
+ " select"
+ " month(i.receiptDate) as invoiceMonth,"
+ " coalesce(sum(i.paidAmount),0) as income"
+ " from project p"
+ " left join invoice i on p.code = i.projectCode"
+ " where p.status = 'On-going'"
+ " and p.id in (:projectIds)"
+ " and year(i.receiptDate) = :year"
+ " and i.id is not null"
+ " group by month(i.receiptDate)"
+ " ) as invoice on months.month = invoice.invoiceMonth"
)

return jdbcDao.queryForList(sql.toString(), args)
}

fun CashFlowMonthlyExpenditureByMonth(args: Map<String, Any>): List<Map<String, Any>> {
val sql = StringBuilder("select"
+ " months.month as monthExpenditure,"
+ " coalesce (expenditure.recordMonth,'-') as recordMonth,"
+ " coalesce (expenditure.expenditure,0) as expenditure,"
+ " SUM(COALESCE(expenditure.expenditure, 0)) OVER (ORDER BY months.month) AS cumulativeExpenditure"
+ " FROM ("
+ " SELECT 01 AS month"
+ " UNION"
+ " SELECT 02"
+ " UNION"
+ " SELECT 03"
+ " UNION"
+ " SELECT 04"
+ " UNION"
+ " SELECT 05"
+ " UNION"
+ " SELECT 06"
+ " UNION"
+ " SELECT 07"
+ " UNION"
+ " SELECT 08"
+ " UNION"
+ " SELECT 09"
+ " UNION"
+ " SELECT 10"
+ " UNION"
+ " SELECT 11"
+ " union"
+ " select 12"
+ " ) AS months"
+ " left join("
+ " SELECT"
+ " r.recordMonth as recordMonth,"
+ " sum(r.cumulativeExpenditure) as expenditure"
+ " from("
+ " select"
+ " month(t.recordDate) as recordMonth,"
+ " (coalesce(sum(t.normalConsumed),0) * s2.hourlyRate) + (coalesce(sum(t.otConsumed),0) * s2.hourlyRate * 1.0) as cumulativeExpenditure"
+ " from project p"
+ " left join project_task pt on p.id = pt.project_id"
+ " left join timesheet t on pt.id = t.projectTaskId"
+ " left join staff s on t.staffId = s.id"
+ " left join salary s2 on s.salaryId = s2.salaryPoint"
+ " where t.id is not null"
+ " and p.id in (:projectIds)"
+ " and year(t.recordDate) = :year"
+ " group by month(t.recordDate),s2.hourlyRate"
+ " ) as r"
+ " group by r.recordMonth"
+ " ) as expenditure on months.month = expenditure.recordMonth"
)

return jdbcDao.queryForList(sql.toString(), args)
}
fun CashFlowReceivableAndExpenditure(args: Map<String, Any>): List<Map<String, Any>> {
val sql = StringBuilder("select"
+ " coalesce (round(sum(i.paidAmount)/sum(i.issueAmount)*100,0),0) as receivedPercentage,"
+ " coalesce (round(expenditure.expenditure/(sum(p.expectedTotalFee)*0.8)*100,0),0) as expenditurePercentage,"
+ " coalesce (sum(i.issueAmount),0) as totalInvoiced,"
+ " coalesce (sum(i.paidAmount),0) as totalReceived,"
+ " coalesce (sum(i.issueAmount) - sum(i.paidAmount),0) as receivable,"
+ " coalesce (round(sum(p.expectedTotalFee)*0.8,2),0) as totalBudget,"
+ " coalesce (expenditure.expenditure) as totalExpenditure,"
+ " coalesce (sum(p.expectedTotalFee)*0.8 - expenditure.expenditure,0) as expenditureReceivable"
+ " from project p"
+ " left join invoice i on p.code = i.projectCode"
+ " left join("
+ " select"
+ " sum(r.expenditure) as expenditure"
+ " from("
+ " select"
+ " (coalesce(sum(t.normalConsumed),0) * s2.hourlyRate) + (coalesce(sum(t.otConsumed),0) * s2.hourlyRate * 1.0) as expenditure"
+ " from project p"
+ " left join project_task pt on p.id = pt.project_id"
+ " left join timesheet t on pt.id = t.projectTaskId"
+ " left join staff s on t.staffId = s.id"
+ " left join salary s2 on s.salaryId = s2.salaryPoint"
+ " where t.id is not null"
+ " and p.id in (:projectIds)"
+ " group by s2.hourlyRate"
+ " ) as r"
+ " ) as expenditure on 1=1"
+ " where p.id in (:projectIds)"
+ " group by expenditure.expenditure"
)

return jdbcDao.queryForList(sql.toString(), args)
}
fun CashFlowAnticipateIncome(args: Map<String, Any>): List<Map<String, Any>> {
val sql = StringBuilder("select"
+ " months.month as monthanticipateIncome,"
+ " coalesce (anticipateIncome.anticipateIncomeDate,'-') as anticipateIncomeDate,"
+ " coalesce (anticipateIncome.anticipateIncome,0) as anticipateIncome"
+ " FROM ("
+ " SELECT 01 AS month"
+ " UNION"
+ " SELECT 02"
+ " UNION"
+ " SELECT 03"
+ " UNION"
+ " SELECT 04"
+ " UNION"
+ " SELECT 05"
+ " UNION"
+ " SELECT 06"
+ " UNION"
+ " SELECT 07"
+ " UNION"
+ " SELECT 08"
+ " UNION"
+ " SELECT 09"
+ " UNION"
+ " SELECT 10"
+ " UNION"
+ " SELECT 11"
+ " union"
+ " select 12"
+ " ) AS months"
+ " left join("
+ " select"
+ " month(mp.date) as anticipateIncomeDate,"
+ " sum(mp.amount) as anticipateIncome"
+ " from project p"
+ " left join milestone m on p.id = m.projectId"
+ " left join milestone_payment mp on m.id = mp.milestoneId"
+ " where p.id in (:projectIds)"
+ " and year(mp.date) = :year"
+ " group by month(mp.date)"
+ " ) as anticipateIncome on months.month = anticipateIncome.anticipateIncomeDate"
)

return jdbcDao.queryForList(sql.toString(), args)
}
fun CashFlowAnticipateExpenditure(args: Map<String, Any>): List<Map<String, Any>> {
val sql = StringBuilder("select"
+ " p.id, p.name,"
+ " date_format(p.planStart, '%Y-%m') as planStart,"
+ " date_format(p.planEnd, '%Y-%m') as planEnd,"
+ " case"
+ " when year(p.planStart) < :year then 1"
+ " when year(p.planStart) = :year then month(p.planStart)"
+ " end as startMonth,"
+ " case"
+ " when year(p.planStart) < :year and year(p.planEnd) > :year then 12"
+ " when year(p.planStart) < :year and year(p.planEnd) = :year then month(p.planEnd)"
+ " when year(p.planStart) = :year and year(p.planEnd) > :year then 12 - month(p.planStart)"
+ " else PERIOD_DIFF(DATE_FORMAT(p.planEnd, '%Y%m'), DATE_FORMAT(p.planStart, '%Y%m'))+1"
+ " end AS 'Duration',"
+ " PERIOD_DIFF(DATE_FORMAT(p.planEnd, '%Y%m'), DATE_FORMAT(p.planStart, '%Y%m'))+1 as projectDuration,"
+ " p.expectedTotalFee*0.8 as totalBudget,"
+ " (p.expectedTotalFee*0.8) / (PERIOD_DIFF(DATE_FORMAT(p.planEnd, '%Y%m'), DATE_FORMAT(p.planStart, '%Y%m'))+1) as aniticipateExpenditure,"
+ " ROUND(p.totalManhour / (PERIOD_DIFF(DATE_FORMAT(p.planEnd, '%Y%m'), DATE_FORMAT(p.planStart, '%Y%m'))+1), 2) AS 'AverageManhours',"
+ " p.teamLead, p.totalManhour"
+ " FROM project p"
+ " WHERE p.status = 'On-going'"
+ " and p.id in (:projectIds)"
+ " and (year(p.planStart) <= :year and year(p.planEnd) >= :year)"
+ " order by teamLead, planStart"
)

return jdbcDao.queryForList(sql.toString(), args)
}
fun CashFlowLedger(args: Map<String, Any>): List<Map<String, Any>> {
val sql = StringBuilder("select"
+ " ROW_NUMBER() OVER (ORDER BY date, income, expenditure) AS id,"
+ " date,"
+ " COALESCE(ROUND(income, 2), 0) AS income,"
+ " COALESCE(ROUND(expenditure, 2), 0) AS expenditure,"
+ " ROUND(SUM(COALESCE(income, 0) - COALESCE(expenditure, 0)) OVER (ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), 2) AS balance,"
+ " CASE"
+ " WHEN income > 0 THEN paymentMilestone"
+ " ELSE 'Monthly Manpower Expenditure'"
+ " END AS remarks"
+ " FROM"
+ " ("
+ " SELECT"
+ " date_format(i.receiptDate, '%b %y') AS date,"
+ " sum(i.paidAmount) AS income,"
+ " NULL AS expenditure,"
+ " i.paymentMilestone AS paymentMilestone"
+ " FROM"
+ " project p"
+ " LEFT JOIN invoice i ON p.code = i.projectCode"
+ " WHERE"
+ " p.id IN (:projectIds)"
+ " AND i.paidAmount IS NOT NULL"
+ " GROUP BY"
+ " date_format(i.receiptDate, '%b %y'),"
+ " i.paymentMilestone"
+ " UNION"
+ " SELECT"
+ " date_format(r.date, '%b %y') AS date,"
+ " NULL AS income,"
+ " sum(r.expenditure) AS expenditure,"
+ " NULL AS paymentMilestone"
+ " FROM"
+ " ("
+ " SELECT"
+ " t.recordDate AS date,"
+ " (COALESCE(SUM(t.normalConsumed), 0) * s2.hourlyRate) + (COALESCE(SUM(t.otConsumed), 0) * s2.hourlyRate * 1.0) AS expenditure"
+ " FROM"
+ " project p"
+ " LEFT JOIN project_task pt ON p.id = pt.project_id"
+ " LEFT JOIN timesheet t ON pt.id = t.projectTaskId"
+ " LEFT JOIN staff s ON t.staffId = s.id"
+ " LEFT JOIN salary s2 ON s.salaryId = s2.salaryPoint"
+ " WHERE"
+ " t.id IS NOT NULL"
+ " AND p.id IN (:projectIds)"
+ " GROUP BY"
+ " s2.hourlyRate,"
+ " t.recordDate"
+ " ) AS r"
+ " GROUP BY"
+ " date_format(r.date, '%b %y')"
+ " ) AS combined_data"
+ " ORDER BY"
+ " date"
)

return jdbcDao.queryForList(sql.toString(), args)
}
fun TeamCashFlowIncome(args: Map<String, Any>): List<Map<String, Any>> {
val sql = StringBuilder("select"
+ " months.month as monthInvoice,"
+ " coalesce (invoice.invoiceMonth,'-') as invoiceMonth,"
+ " coalesce (invoice.income,0) as income,"
+ " SUM(COALESCE(invoice.income, 0)) OVER (ORDER BY months.month) AS cumulativeIncome"
+ " FROM ("
+ " SELECT 01 AS month"
+ " UNION"
+ " SELECT 02"
+ " UNION"
+ " SELECT 03"
+ " UNION"
+ " SELECT 04"
+ " UNION"
+ " SELECT 05"
+ " UNION"
+ " SELECT 06"
+ " UNION"
+ " SELECT 07"
+ " UNION"
+ " SELECT 08"
+ " UNION"
+ " SELECT 09"
+ " UNION"
+ " SELECT 10"
+ " UNION"
+ " SELECT 11"
+ " union"
+ " select 12"
+ " ) AS months"
+ " left join("
+ " select"
+ " month(i.receiptDate) as invoiceMonth,"
+ " coalesce(sum(i.paidAmount),0) as income"
+ " from project p"
+ " left join team t on p.teamLead = t.teamLead"
+ " left join invoice i on p.code = i.projectCode"
+ " where p.status = 'On-going'"

)

if (args != null) {
if (args.containsKey("teamId"))
sql.append(" AND t.id = :teamId")
}
sql.append(" and year(i.receiptDate) = :year"
+ " and i.id is not null"
+ " group by month(i.receiptDate)"
+ " ) as invoice on months.month = invoice.invoiceMonth")

return jdbcDao.queryForList(sql.toString(), args)
}
fun TeamCashFlowExpenditure(args: Map<String, Any>): List<Map<String, Any>> {
val sql = StringBuilder("select"
+ " months.month as monthExpenditure,"
+ " coalesce (expenditure.recordMonth,'-') as recordMonth,"
+ " coalesce (expenditure.expenditure,0) as expenditure,"
+ " SUM(COALESCE(expenditure.expenditure, 0)) OVER (ORDER BY months.month) AS cumulativeExpenditure"
+ " FROM ("
+ " SELECT 01 AS month"
+ " UNION"
+ " SELECT 02"
+ " UNION"
+ " SELECT 03"
+ " UNION"
+ " SELECT 04"
+ " UNION"
+ " SELECT 05"
+ " UNION"
+ " SELECT 06"
+ " UNION"
+ " SELECT 07"
+ " UNION"
+ " SELECT 08"
+ " UNION"
+ " SELECT 09"
+ " UNION"
+ " SELECT 10"
+ " UNION"
+ " SELECT 11"
+ " union"
+ " select 12"
+ " ) AS months"
+ " left join("
+ " SELECT"
+ " r.recordMonth as recordMonth,"
+ " sum(r.cumulativeExpenditure) as expenditure"
+ " from("
+ " select"
+ " month(t.recordDate) as recordMonth,"
+ " (coalesce(sum(t.normalConsumed),0) * s2.hourlyRate) + (coalesce(sum(t.otConsumed),0) * s2.hourlyRate * 1.0) as cumulativeExpenditure"
+ " from project p"
+ " left join team t2 on p.teamLead = t2.teamLead"
+ " left join project_task pt on p.id = pt.project_id"
+ " left join timesheet t on pt.id = t.projectTaskId"
+ " left join staff s on t.staffId = s.id"
+ " left join salary s2 on s.salaryId = s2.salaryPoint"
+ " where t.id is not null"
)
if (args != null) {
if (args.containsKey("teamId"))
sql.append(" AND t2.id = :teamId")
}
sql.append(" and year(t.recordDate) = :year"
+ " group by month(t.recordDate),s2.hourlyRate"
+ " ) as r"
+ " group by r.recordMonth"
+ " ) as expenditure on months.month = expenditure.recordMonth")

return jdbcDao.queryForList(sql.toString(), args)
}

}



+ 13
- 16
src/main/java/com/ffii/tsms/modules/data/service/TeamService.kt Wyświetl plik

@@ -41,15 +41,15 @@ open class TeamService(
val ids = req.addStaffIds!!
// println(ids)
val teamLead = staffRepository.findById(ids[0]).orElseThrow()
val teamName = "Team " + teamLead.name
val initials = teamLead.name.split(" ").map { it.first() }
val teamCode = initials.joinToString("")
// val teamName = "Team " + teamLead.name
//
// val initials = teamLead.name.split(" ").map { it.first() }
// val teamCode = initials.joinToString("")

val team = Team().apply {
this.staff = teamLead
name = teamName
code = teamCode
name = req.name
code = req.code
description = req.description
}
teamRepository.saveAndFlush(team)
@@ -68,26 +68,23 @@ open class TeamService(
val addIds = req.addStaffIds ?: listOf<Int>()

val teamLead: Staff
val teamName: String
val teamCode: String
// val teamName: String
// val teamCode: String

if (addIds.isNotEmpty()) {
val leader = staffRepository.findById(addIds[0].toLong()).orElseThrow()
teamName = "Team " + leader.name
// teamName = "Team " + leader.name
teamLead = leader;

val initials = leader.name.split(" ").map { it.first() }
teamCode = initials.joinToString("")
// val initials = leader.name.split(" ").map { it.first() }
// teamCode = initials.joinToString("")
} else {
teamLead = team.staff
teamName = team.name
teamCode = team.code
}

team.apply {
this.staff = teamLead
name = teamName
code = teamCode
name = req.name
code = req.code
description = req.description
}



+ 76
- 0
src/main/java/com/ffii/tsms/modules/data/web/DashboardController.kt Wyświetl plik

@@ -131,4 +131,80 @@ class DashboardController(
val args = mutableMapOf<String, Any>()
return dashboardService.CashFlowProject(args)
}
@GetMapping("/searchCashFlowByMonth")
fun searchCashFlowByMonth(request: HttpServletRequest?): List<Map<String, Any>> {
val args = mutableMapOf<String, Any>()
val projectIdList = request?.getParameter("projectIdList")
val year = request?.getParameter("year")
val projectIds = projectIdList?.split(",")?.map { it.toInt() }?.toList()
if (projectIds != null) {
args["projectIds"] = projectIds
}
if (year != null) {
args["year"] = year
}
val result = mutableMapOf<String, Any>()
val cashFlowMonthlyIncome = dashboardService.CashFlowMonthlyIncomeByMonth(args)
val cashFlowMonthlyExpenditure = dashboardService.CashFlowMonthlyExpenditureByMonth(args)
result["incomeList"] = cashFlowMonthlyIncome
result["expenditureList"] = cashFlowMonthlyExpenditure
return listOf(result)
}
@GetMapping("/searchCashFlowReceivableAndExpenditure")
fun searchCashFlowReceivableAndExpenditure(request: HttpServletRequest?): List<Map<String, Any>> {
val args = mutableMapOf<String, Any>()
val projectIdList = request?.getParameter("projectIdList")
val projectIds = projectIdList?.split(",")?.map { it.toInt() }?.toList()
if (projectIds != null) {
args["projectIds"] = projectIds
}
return dashboardService.CashFlowReceivableAndExpenditure(args)
}
@GetMapping("/searchCashFlowAnticipate")
fun searchCashFlowAnticipate(request: HttpServletRequest?): List<Map<String, Any>> {
val args = mutableMapOf<String, Any>()
val projectIdList = request?.getParameter("projectIdList")
val year = request?.getParameter("year")
val projectIds = projectIdList?.split(",")?.map { it.toInt() }?.toList()
if (projectIds != null) {
args["projectIds"] = projectIds
}
if (year != null) {
args["year"] = year
}
val result = mutableMapOf<String, Any>()
val cashFlowAnticipateIncome = dashboardService.CashFlowAnticipateIncome(args)
val cashFlowAnticipateExpenditure = dashboardService.CashFlowAnticipateExpenditure(args)
result["anticipateIncomeList"] = cashFlowAnticipateIncome
result["anticipateExpenditureList"] = cashFlowAnticipateExpenditure
return listOf(result)
}
@GetMapping("/searchCashFlowLedger")
fun searchCashFlowLedger(request: HttpServletRequest?): List<Map<String, Any>> {
val args = mutableMapOf<String, Any>()
val projectIdList = request?.getParameter("projectIdList")
val projectIds = projectIdList?.split(",")?.map { it.toInt() }?.toList()
if (projectIds != null) {
args["projectIds"] = projectIds
}
return dashboardService.CashFlowLedger(args)
}
@GetMapping("/searchTeamCashFlow")
fun searchTeamCashFlow(request: HttpServletRequest?): List<Map<String, Any>> {
val args = mutableMapOf<String, Any>()
val teamId = request?.getParameter("teamId")
val year = request?.getParameter("year")
if (teamId != null) {
args["teamId"] = teamId
}
if (year != null) {
args["year"] = year
}
val result = mutableMapOf<String, Any>()
val teamCashFlowIncome = dashboardService.TeamCashFlowIncome(args)
val teamCashFlowExpenditure = dashboardService.TeamCashFlowExpenditure(args)
result["teamCashFlowIncome"] = teamCashFlowIncome
result["teamCashFlowExpenditure"] = teamCashFlowExpenditure
return listOf(result)
}
}

+ 22
- 1
src/main/java/com/ffii/tsms/modules/data/web/TeamController.kt Wyświetl plik

@@ -1,8 +1,11 @@
package com.ffii.tsms.modules.data.web

import com.ffii.core.exception.NotFoundException
import com.ffii.core.response.RecordsRes
import com.ffii.core.utils.CriteriaArgsBuilder
import com.ffii.core.utils.Params
import com.ffii.tsms.modules.data.entity.Team
import com.ffii.tsms.modules.data.service.StaffsService
import com.ffii.tsms.modules.data.service.TeamService
import com.ffii.tsms.modules.data.web.models.NewTeamRequest
import jakarta.servlet.http.HttpServletRequest
@@ -15,7 +18,10 @@ import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/team")
class TeamController(private val teamService: TeamService) {
class TeamController(
private val teamService: TeamService,
private val staffsService: StaffsService,
) {

@GetMapping
fun allStaff(args: Map<String, Any>): List<Map<String, Any>> {
@@ -34,6 +40,21 @@ class TeamController(private val teamService: TeamService) {
return teamService.getTeamDetail(args);
}

@GetMapping("/{id}")
fun getStaff(@PathVariable id: Long): Map<String, Any> {
val staffList = staffsService.findAllByTeamId(id).orElseThrow { NotFoundException() }
val staffIdList: MutableList<Long> = mutableListOf()
for (staff in staffList) {
staffIdList.add(staff.id as Long)
}
// val map: Map<String, Any> = java.util.Map.of("team" to teamService.find(id).orElseThrow { NotFoundException() })
// map["staffIds"] = staffIdList
return java.util.Map.of(
"team", staffsService.find(id).orElseThrow { NotFoundException() },
"staffIds", staffIdList
)
}

// @Transactional(rollbackFor = [Exception::class])
@DeleteMapping("/delete/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)


+ 5
- 5
src/main/java/com/ffii/tsms/modules/data/web/models/NewStaffRequest.kt Wyświetl plik

@@ -13,21 +13,21 @@ data class NewStaffRequest(
val companyId: Long,
@field:NotNull(message = "Staff salaryId cannot be empty")
val salaryId: Long,
@field:NotNull(message = "joinDate cannot be empty")
// @field:NotNull(message = "joinDate cannot be empty")
val joinDate: LocalDate,
@field:NotNull(message = "Staff currentPositionId cannot be empty")
val currentPositionId: Long,
@field:NotNull(message = "Staff joinPositionId cannot be empty")
// @field:NotNull(message = "Staff joinPositionId cannot be empty")
val joinPositionId: Long,
@field:NotNull(message = "Staff departmentId cannot be empty")
// @field:NotNull(message = "Staff departmentId cannot be empty")
val departmentId: Long,
@field:NotBlank(message = "Staff phone1 cannot be empty")
val phone1: String,
@field:NotBlank(message = "Staff email cannot be empty")
val email: String,
@field:NotBlank(message = "Staff emergContactName cannot be empty")
// @field:NotBlank(message = "Staff emergContactName cannot be empty")
val emergContactName: String,
@field:NotBlank(message = "Staff emergContactPhone cannot be empty")
// @field:NotBlank(message = "Staff emergContactPhone cannot be empty")
val emergContactPhone: String,
@field:NotBlank(message = "Staff employType cannot be empty")
val employType: String,


+ 2
- 1
src/main/java/com/ffii/tsms/modules/data/web/models/NewTeamRequest.kt Wyświetl plik

@@ -6,7 +6,8 @@ import java.time.LocalDate

data class NewTeamRequest (
val addStaffIds: List<Long>?,

val name: String,
val code: String,
val deleteStaffIds: List<Long>?,
val description: String?,
val id: Long?

+ 6
- 1
src/main/java/com/ffii/tsms/modules/project/entity/ProjectRepository.kt Wyświetl plik

@@ -1,10 +1,13 @@
package com.ffii.tsms.modules.project.entity;

import com.ffii.core.support.AbstractRepository
import com.ffii.tsms.modules.data.entity.Customer
import com.ffii.tsms.modules.data.entity.Staff
import com.ffii.tsms.modules.project.entity.projections.InvoiceInfoSearchInfo
import com.ffii.tsms.modules.project.entity.projections.InvoiceSearchInfo
import com.ffii.tsms.modules.project.entity.projections.ProjectSearchInfo
import org.springframework.data.jpa.repository.Query
import org.springframework.lang.Nullable
import java.io.Serializable
import java.time.LocalDate

@@ -25,8 +28,10 @@ interface ProjectRepository : AbstractRepository<Project, Long> {
"")
fun getLatestCodeNumberByMainProject(isClpProject: Boolean, id: Serializable?): Long?

@Query("SELECT max(case when length(p.code) - length(replace(p.code, '-', '')) > 1 then cast(substring_index(p.code, '-', -1) as long) end) FROM Project p WHERE p.code like ?1 and p.id != ?2")
@Query("SELECT max(case when length(p.code) - length(replace(p.code, '-', '')) > 1 then cast(substring_index(p.code, '-', -1) as long) end) FROM Project p WHERE p.code like %?1% and p.id != ?2")
fun getLatestCodeNumberBySubProject(code: String, id: Serializable?): Long?

fun findAllByStatusIsNotAndMainProjectIsNull(status: String): List<Project>

fun findAllByTeamLeadAndCustomer(teamLead: Staff, customer: Customer): List<Project>
}

+ 1
- 0
src/main/java/com/ffii/tsms/modules/project/entity/ProjectTaskRepository.kt Wyświetl plik

@@ -5,5 +5,6 @@ import com.ffii.core.support.AbstractRepository
interface ProjectTaskRepository : AbstractRepository<ProjectTask, Long> {
fun findAllByProject(project: Project): List<ProjectTask>

fun findAllByProjectIn(projects: List<Project>): List<ProjectTask>
fun findByProjectAndTask(project: Project, task: Task): ProjectTask?
}

+ 629
- 281
src/main/java/com/ffii/tsms/modules/report/service/ReportService.kt
Plik diff jest za duży
Wyświetl plik


+ 48
- 8
src/main/java/com/ffii/tsms/modules/report/web/ReportController.kt Wyświetl plik

@@ -2,11 +2,9 @@ package com.ffii.tsms.modules.report.web

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.ffii.tsms.modules.data.entity.Customer
import com.ffii.tsms.modules.data.entity.StaffRepository
import com.ffii.tsms.modules.data.entity.*
//import com.ffii.tsms.modules.data.entity.projections.FinancialStatusReportInfo
import com.ffii.tsms.modules.data.entity.projections.StaffSearchInfo
import com.ffii.tsms.modules.data.entity.Team
import com.ffii.tsms.modules.data.service.CustomerService
import com.ffii.tsms.modules.data.service.TeamService
import com.ffii.tsms.modules.project.entity.*
@@ -35,11 +33,13 @@ import java.time.LocalDate
import java.net.URLEncoder
import java.time.format.DateTimeFormatter
import org.springframework.stereotype.Controller
import com.ffii.tsms.modules.data.entity.TeamRepository
import com.ffii.tsms.modules.data.entity.CustomerRepository
import org.springframework.data.jpa.repository.JpaRepository
import com.ffii.tsms.modules.project.entity.Project
import com.ffii.tsms.modules.report.web.model.*
import com.ffii.tsms.modules.timesheet.entity.Timesheet
import org.springframework.data.domain.Example
import org.springframework.data.domain.ExampleMatcher
import java.time.temporal.ChronoUnit

@RestController
@RequestMapping("/reports")
@@ -56,7 +56,8 @@ class ReportController(
private val leaveRepository: LeaveRepository,
private val teamService: TeamService,
private val customerService: CustomerService,
private val invoiceService: InvoiceService) {
private val invoiceService: InvoiceService, private val gradeAllocationRepository: GradeAllocationRepository
) {

@PostMapping("/fetchProjectsFinancialStatusReport")
@Throws(ServletRequestBindingException::class, IOException::class)
@@ -87,6 +88,34 @@ class ReportController(
.body(ByteArrayResource(reportResult))
}

@PostMapping("/ProjectPotentialDelayReport")
@Throws(ServletRequestBindingException::class, IOException::class)
fun getProjectPotentialDelayReport(@RequestBody @Valid request: ProjectPotentialDelayReportRequest): ResponseEntity<Resource> {

val team = if (request.teamId.lowercase() == "all") null else teamRepository.findById(request.teamId.toLong()).orElse(null)
val searchedTeam = if (team == null) "All" else team.code + " - " +team.name
val client = if (request.clientId.lowercase() == "all") null else customerRepository.findById(request.clientId.toLong()).orElse(null)
val searchedClient = if (client == null) "All" else client.code + " - " +client.name

val matcher = ExampleMatcher.matching().withIgnoreNullValues()
val exampleQuery = Example.of(Project().apply {
// org.springframework.dao.InvalidDataAccessApiUsageException: Path 'teamLead.team.staff' from root Project must not span a cyclic property reference
// [{ com.ffii.tsms.modules.project.entity.Project@6847e037 }] -teamLead-> [{ com.ffii.tsms.modules.data.entity.Staff@2a4c488b }] -team-> [{ com.ffii.tsms.modules.data.entity.Team@a09acb5 }] -staff-> [{ com.ffii.tsms.modules.data.entity.Staff@2a4c488b }]
// teamLead = team?.staff
customer = client
status = "On-going"
}, matcher)

val projects = if (team == null) projectRepository.findAll(exampleQuery) else projectRepository.findAll(exampleQuery).filter { it.teamLead == team.staff }
val projectTasks = projectTaskRepository.findAllByProjectIn(projects)
val timesheets = timesheetRepository.findAllByProjectTaskIn(projectTasks)

val reportResult: ByteArray = excelReportService.generateProjectPotentialDelayReport(searchedTeam, searchedClient, projects, timesheets, request.numberOfDays, request.projectCompletion)
return ResponseEntity.ok()
.header("filename", "Project Potential Delay Report - " + LocalDate.now() + ".xlsx")
.body(ByteArrayResource(reportResult))
}

@PostMapping("/StaffMonthlyWorkHourAnalysisReport")
@Throws(ServletRequestBindingException::class, IOException::class)
fun StaffMonthlyWorkHourAnalysisReport(@RequestBody @Valid request: StaffMonthlyWorkHourAnalysisReportRequest): ResponseEntity<Resource> {
@@ -262,8 +291,19 @@ class ReportController(
}

@GetMapping("/costNExpenses/{status}")
fun getManhoursSpent(@PathVariable status: String): List<Map<String, Any?>> {
return excelReportService.getCostAndExpense("All")
fun getManhoursSpent(@RequestBody @Valid request: costAndExpenseRequest): List<Map<String, Any?>> {
return excelReportService.getCostAndExpense(request.clientId, request.teamId)
}

@PostMapping("/costandexpenseReport")
@Throws(ServletRequestBindingException::class, IOException::class)
fun getCostAndExpenseReport(@RequestBody @Valid request: costAndExpenseRequest): ResponseEntity<Resource> {
println(request)
val reportResult: ByteArray = excelReportService.genCostAndExpenseReport(request)

return ResponseEntity.ok()
.header("filename", "Cost and Expense Report - " + LocalDate.now() + ".xlsx")
.body(ByteArrayResource(reportResult))
}

}

+ 13
- 0
src/main/java/com/ffii/tsms/modules/report/web/model/ReportRequest.kt Wyświetl plik

@@ -13,11 +13,24 @@ data class PandLReportRequest (
val endMonth: String,
)

data class costAndExpenseRequest (
val teamId: Long?,
val clientId: Long?,
val budgetPercentage: Double?,
)

data class ProjectCashFlowReportRequest (
val projectId: Long,
val dateType: String, // "Date", "Month"
)

data class ProjectPotentialDelayReportRequest (
val teamId: String,
val clientId: String,
val numberOfDays: Int,
val projectCompletion: Int,
)

data class StaffMonthlyWorkHourAnalysisReportRequest (
val id: Long,
val yearMonth: YearMonth


+ 5
- 0
src/main/java/com/ffii/tsms/modules/timesheet/entity/Timesheet.kt Wyświetl plik

@@ -2,6 +2,7 @@ package com.ffii.tsms.modules.timesheet.entity

import com.ffii.core.entity.BaseEntity
import com.ffii.tsms.modules.data.entity.Staff
import com.ffii.tsms.modules.project.entity.Project
import com.ffii.tsms.modules.project.entity.ProjectTask
import jakarta.persistence.*
import jakarta.validation.constraints.NotNull
@@ -29,6 +30,10 @@ open class Timesheet : BaseEntity<Long>() {
@JoinColumn(name = "projectTaskId")
open var projectTask: ProjectTask? = null

@ManyToOne
@JoinColumn(name = "projectId")
open var project: Project? = null

@Column(name = "remark")
open var remark: String? = null
}

+ 3
- 1
src/main/java/com/ffii/tsms/modules/timesheet/service/TimesheetsService.kt Wyświetl plik

@@ -46,6 +46,7 @@ open class TimesheetsService(
this.normalConsumed = timeEntry.inputHours
this.otConsumed = timeEntry.otHours
this.projectTask = projectTask
this.project = project
this.remark = timeEntry.remark
}
}
@@ -72,6 +73,7 @@ open class TimesheetsService(
this.normalConsumed = entry.inputHours
this.otConsumed = entry.otHours
this.projectTask = projectTask
this.project = project
this.remark = entry.remark
this.recordDate = this.recordDate ?: recordDate
this.staff = this.staff ?: memberStaff
@@ -112,7 +114,7 @@ open class TimesheetsService(
.mapValues { (_, timesheets) -> timesheets.map { timesheet ->
TimeEntry(
id = timesheet.id!!,
projectId = timesheet.projectTask?.project?.id,
projectId = timesheet.projectTask?.project?.id ?: timesheet.project?.id,
taskId = timesheet.projectTask?.task?.id,
taskGroupId = timesheet.projectTask?.task?.taskGroup?.id,
inputHours = timesheet.normalConsumed ?: 0.0,


+ 6
- 0
src/main/java/com/ffii/tsms/modules/user/req/UpdateUserReq.java Wyświetl plik

@@ -18,6 +18,9 @@ public class UpdateUserReq {
@NotBlank
private String name;

@NotBlank
private String username;

private String firstname;
private String lastname;
private LocalDate expiryDate;
@@ -55,6 +58,9 @@ public class UpdateUserReq {
public void setName(String name) {
this.name = name;
}
public String getUsername() { return username; }

public void setUsername(String username) { this.username = username; }

public LocalDate getExpiryDate() {
return expiryDate;


+ 0
- 33
src/main/resources/db/changelog/changes/20240318_01_wayne/02_mock_team_leads.sql Wyświetl plik

@@ -1,35 +0,0 @@
INSERT INTO `user` (name, username, password) VALUES
('Wayne Lee','wlee','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Ming Chan','mchan','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi');
INSERT INTO company (companyCode, name) VALUES
('ABC', 'Company ABC');
INSERT INTO team (name, code) VALUES
('Team Wayne Lee', 'WL'),
('Team Ming Chan', 'MC');
INSERT INTO salary_effective (date, salaryId) VALUES
(current_date, 1);
INSERT INTO staff (userId, name, staffId, companyId, teamId, salaryEffId) VALUES
(
(SELECT id from `user` where username = 'wlee'),
'Wayne Lee',
'001',
(SELECT id from company where companyCode = 'ABC'),
(SELECT id from team where code = 'WL'),
(SELECT id from salary_effective where salaryId = 1)
),
(
(SELECT id from `user` where username = 'mchan'),
'Ming Chan',
'002',
(SELECT id from company where companyCode = 'ABC'),
(SELECT id from team where code = 'MC'),
(SELECT id from salary_effective where salaryId = 1)
);

+ 0
- 112
src/main/resources/db/changelog/changes/20240414_01_wayne/01_mock_staffs.sql Wyświetl plik

@@ -1,114 +0,0 @@

INSERT INTO `user` (name, username, password) VALUES
('Albert Lam','alam','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Bernard Chou','bchou','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Carl Junior','cjunior','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Denis Lau','dlau','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Edward Wong','ewong','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Fred Cheung','fcheung','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Gordon Ramsey','gramsey','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Heather Stewards','hstewards','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Ivan Foo','ifoo','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Jack Son','json','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Kurt Land','kland','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi'),
('Lawrence Arnold','larnold','$2a$10$65S7/AhKn8MldlYmvFN5JOfr1yaULwFNDIhTskLTuUCKgbbs8sFAi');

INSERT INTO staff (userId, name, staffId, companyId, teamId, salaryEffId) VALUES
(
(SELECT id from `user` where username = 'alam'),
'Albert Lam',
'003',
1,
1,
1
),
(
(SELECT id from `user` where username = 'bchou'),
'Bernard Chou',
'004',
1,
2,
1
),
(
(SELECT id from `user` where username = 'cjunior'),
'Carl Junior',
'005',
1,
1,
1
),
(
(SELECT id from `user` where username = 'dlau'),
'Denis Lau',
'006',
1,
2,
1
),
(
(SELECT id from `user` where username = 'ewong'),
'Edward Wong',
'007',
1,
1,
1
),
(
(SELECT id from `user` where username = 'fcheung'),
'Fred Cheung',
'008',
1,
2,
1
),
(
(SELECT id from `user` where username = 'gramsey'),
'Gordon Ramsey',
'009',
1,
1,
1
),
(
(SELECT id from `user` where username = 'hstewards'),
'Heather Stewards',
'010',
1,
2,
1
),
(
(SELECT id from `user` where username = 'ifoo'),
'Ivan Foo',
'011',
1,
1,
1
),
(
(SELECT id from `user` where username = 'json'),
'Jack Son',
'012',
1,
2,
1
),
(
(SELECT id from `user` where username = 'kland'),
'Kurt Land',
'013',
1,
1,
1
),
(
(SELECT id from `user` where username = 'larnold'),
'Lawrence Arnold',
'014',
1,
2,
1
);

+ 6
- 0
src/main/resources/db/changelog/changes/20240525_01_wayne/01_timesheet_project.sql Wyświetl plik

@@ -0,0 +1,6 @@
-- liquibase formatted sql
-- changeset wayne:timesheet_project

ALTER TABLE timesheet ADD projectId INT NULL;

ALTER TABLE timesheet ADD CONSTRAINT FK_TIMESHEET_ON_PROJECTID FOREIGN KEY (projectId) REFERENCES project (id);

+ 123
- 0
src/main/resources/db/changelog/changes/20240527_01_cyril/01_update_task.sql Wyświetl plik

@@ -0,0 +1,123 @@
-- liquibase formatted sql
-- changeset cyril:task

UPDATE task
SET name='1.1 Prepare / revise Cost Estimate / Cost Plan'
WHERE id=1;
UPDATE task
SET name='1.2 Cost estimation and cost studies'
WHERE id=2;
UPDATE task
SET name='1.3 Cash flow forecast'
WHERE id=3;
UPDATE task
SET name='1.4 Attend meetings'
WHERE id=4;
UPDATE task
SET name='2.1 Advise on tendering, contractual and procurement arrangement',taskGroupId=2
WHERE id=5;
UPDATE task
SET name='2.2 Drafting / vetting front-part'
WHERE id=6;
UPDATE task
SET name='2.3 Carry out pre-qualification exercise / EOI'
WHERE id=7;
UPDATE task
SET name='2.4 Measurement & billing for 1st tender out'
WHERE id=8;
UPDATE task
SET name='2.5 Measurement & billing for tender addendum'
WHERE id=9;
UPDATE task
SET name='2.6 Bulk checking'
WHERE id=10;
UPDATE task
SET name='2.7 Edit tender documents (Incl. Bills of Quantities / SOR)'
WHERE id=11;
UPDATE task
SET name='2.8 Preparation of pre-tender estimates'
WHERE id=12;
UPDATE task
SET name='2.9 Update cash flow forecast'
WHERE id=13;
UPDATE task
SET name='2.10 Attend meetings'
WHERE id=14;
UPDATE task
SET name='3.1 Evaluation of tenders (incl. rate analysis)',taskGroupId=3
WHERE id=15;
UPDATE task
SET name='3.2 Preparation of tender queries',taskGroupId=3
WHERE id=16;
UPDATE task
SET name='3.3 Attend tender interviews'
WHERE id=17;
UPDATE task
SET name='3.4 Preparation of Report on Tenderers'
WHERE id=18;
UPDATE task
SET name='3.5 Draft Letter of Acceptance / Award'
WHERE id=19;
UPDATE task
SET name='3.6 Preparation of Contract Documents'
WHERE id=20;
UPDATE task
SET name='4.1 Check insurance policies, surety bond, guarantee, etc.',taskGroupId=4
WHERE id=21;
UPDATE task
SET name='4.2 Valuation for interim/final payments (incl. site visits)',taskGroupId=4
WHERE id=22;
UPDATE task
SET name='4.3 Preparation of financial statements (incl. cash flow forecasts)',taskGroupId=4
WHERE id=23;
UPDATE task
SET name='4.4 Cost check / advice on alterative design solutions'
WHERE id=24;
UPDATE task
SET name='4.5 Cost estimation for draft AIs/EIs/SIs'
WHERE id=25;
UPDATE task
SET name='4.6 Advise on contractual issues & evaluate monetary claims'
WHERE id=26;
UPDATE task
SET name='4.7 Measurement & valuation of variations / prime cost & provisional sums'
WHERE id=27;
UPDATE task
SET name='4.8 Negotiation and settlement of final accounts (incl. meetings)'
WHERE id=28;
UPDATE task
SET name='4.9 Preparation of Statement of Final Account'
WHERE id=29;
UPDATE task
SET name='4.10 Preparation of Cost Analysis for the completed project'
WHERE id=30;
UPDATE task
SET name='4.11 Check / review draft final bills'
WHERE id=31;
UPDATE task
SET name='4.12 Carry out site check for draft final bills'
WHERE id=32;
UPDATE task
SET name='4.13 Attend meetings (other than final account meetings)'
WHERE id=33;
UPDATE task
SET name='5.1 Preparation of Fee Proposal / EOI',taskGroupId=5
WHERE id=34;
UPDATE task
SET name='5.2 Attend Management Meeting / Management Workshop',taskGroupId=5
WHERE id=35;
UPDATE task
SET name='5.3 Preparation of project budget i.e. manhours vs fee receivables',taskGroupId=5
WHERE id=36;
UPDATE task
SET name='5.4 Attend Local / International Conference / Seminar / Webinar'
WHERE id=37;
UPDATE task
SET name='5.5 Preparing supplementary agreements (SA)'
WHERE id=38;
UPDATE task
SET name='5.6 Measurement / ad hoc tasks for Contractor'
WHERE id=39;
UPDATE task
SET name='5.7 Management Timesheet Allocation'
WHERE id=40;

+ 74
- 0
src/main/resources/db/changelog/changes/20240527_01_cyril/02_update_position.sql Wyświetl plik

@@ -0,0 +1,74 @@
-- liquibase formatted sql
-- changeset cyril:position

INSERT INTO position (description,name,code)
VALUES ('Resident Quantity Surveyor','Resident Quantity Surveyor','Resident QS');
INSERT INTO position (description,name,code)
VALUES ('Resident AQS','Resident AQS','Resident AQS');
INSERT INTO position (description,name,code)
VALUES ('Administrative Officer','Administrative Officer','Admin Officer');
INSERT INTO position (description,name,code)
VALUES ('Secretary','Secretary','Secretary');
INSERT INTO position (description,name,code)
VALUES ('CPMS Assessor','CPMS Assessor','CPMS Assessor');
INSERT INTO position (description,name,code)
VALUES ('Co-ordinator','Co-ordinator','Co-ordinator');
INSERT INTO position (description,name,code)
VALUES ('Admin Supporter','Admin Supporter','Admin Supporter');
INSERT INTO position (description,name,code)
VALUES ('Receptionist','Receptionist','Receptionist');
INSERT INTO position (description,name,code)
VALUES ('Junior Secretary','Junior Secretary','Junior Secretary');
INSERT INTO position (description,name,code)
VALUES ('Clerk','Clerk','Clerk');
INSERT INTO position (description,name,code)
VALUES ('Office Assistant','Office Assistant','Office Assistant');
INSERT INTO position (description,name,code)
VALUES ('HR Assistant','HR Assistant','HR Assistant');
INSERT INTO position (description,name,code)
VALUES ('Project Officer','Project Officer','Project Officer');
INSERT INTO position (description,name,code)
VALUES ('Ex. Secretary','Ex. Secretary','Ex. Secretary');
INSERT INTO position (description,name,code)
VALUES ('I.T. Officer','I.T. Officer','I.T. Officer');
INSERT INTO position (description,name,code)
VALUES ('Resident Senior Quantity Surveyor','Resident Senior Quantity Surveyor','Resident SQS');
INSERT INTO position (description,name,code)
VALUES ('Obsever (SQS)','Obsever (SQS)','Obsever (SQS)');
INSERT INTO position (description,name,code)
VALUES ('HR Manager','HR Manager','HR Manager');
INSERT INTO position (description,name,code)
VALUES ('Senior Consultant','Senior Consultant','Senior Consultant');
UPDATE position
SET description='Quantity Surveying Trainee'
WHERE id=1;
UPDATE position
SET name='Assistant Quantity Surveyor',description='Assistant Quantity Surveyor',code='AQS'
WHERE id=2;
UPDATE position
SET name='Quantity Surveyor',description='Quantity Surveyor'
WHERE id=3;
UPDATE position
SET name='Senior Quantity Surveyor',description='Senior Quantity Surveyor',code='SQS'
WHERE id=4;
UPDATE position
SET description='Assistant Manager'
WHERE id=5;
UPDATE position
SET description='Deputy Manager'
WHERE id=6;
UPDATE position
SET description='Manager'
WHERE id=7;
UPDATE position
SET description='Senior Manager'
WHERE id=8;
UPDATE position
SET description='Assistant Director'
WHERE id=9;
UPDATE position
SET description='Deputy Director'
WHERE id=10;
UPDATE position
SET description='Director'
WHERE id=11;

BIN
src/main/resources/templates/report/AR02_Delay Report v02.xlsx Wyświetl plik


BIN
src/main/resources/templates/report/AR03_Resource Overconsumption.xlsx Wyświetl plik


BIN
src/main/resources/templates/report/AR04_Cost and Expense Report v02.xlsx Wyświetl plik


BIN
src/main/resources/templates/report/AR05_Project Completion Report.xlsx Wyświetl plik


BIN
src/main/resources/templates/report/AR06_Project Completion Report with Outstanding Accounts Receivable v02.xlsx Wyświetl plik


BIN
src/main/resources/templates/report/AR07_Project P&L Report v02.xlsx Wyświetl plik


BIN
src/main/resources/templates/report/AR08_Monthly Work Hours Analysis Report.xlsx Wyświetl plik


BIN
src/main/resources/templates/report/EX01_Financial Status Report.xlsx Wyświetl plik


BIN
src/main/resources/templates/report/EX02_Project Cash Flow Report.xlsx Wyświetl plik


Ładowanie…
Anuluj
Zapisz