|
|
@@ -3,6 +3,7 @@ package com.ffii.fpsms.modules.chart.service |
|
|
import com.ffii.core.support.JdbcDao |
|
|
import com.ffii.core.support.JdbcDao |
|
|
import org.springframework.stereotype.Service |
|
|
import org.springframework.stereotype.Service |
|
|
import java.time.LocalDate |
|
|
import java.time.LocalDate |
|
|
|
|
|
import java.time.LocalDateTime |
|
|
|
|
|
|
|
|
@Service |
|
|
@Service |
|
|
open class ChartService( |
|
|
open class ChartService( |
|
|
@@ -15,25 +16,18 @@ open class ChartService( |
|
|
*/ |
|
|
*/ |
|
|
fun getStockTransactionsByDate(startDate: LocalDate?, endDate: LocalDate?): List<Map<String, Any>> { |
|
|
fun getStockTransactionsByDate(startDate: LocalDate?, endDate: LocalDate?): List<Map<String, Any>> { |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val startSql = if (startDate != null) { |
|
|
|
|
|
args["startDate"] = startDate.toString() |
|
|
|
|
|
"AND DATE(sl.date) >= :startDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
val endSql = if (endDate != null) { |
|
|
|
|
|
args["endDate"] = endDate.toString() |
|
|
|
|
|
"AND DATE(sl.date) <= :endDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
|
|
|
val rangeSql = ledgerDateTimeRangeSql(args, "sl.date", startDate, endDate) |
|
|
val sql = """ |
|
|
val sql = """ |
|
|
SELECT |
|
|
SELECT |
|
|
DATE_FORMAT(sl.date, '%Y-%m-%d') AS date, |
|
|
DATE_FORMAT(sl.date, '%Y-%m-%d') AS date, |
|
|
COALESCE(SUM(sl.inQty), 0) AS inQty, |
|
|
COALESCE(SUM(sl.inQty), 0) AS inQty, |
|
|
COALESCE(SUM(sl.outQty), 0) AS outQty, |
|
|
COALESCE(SUM(sl.outQty), 0) AS outQty, |
|
|
COALESCE(SUM(COALESCE(sl.inQty, 0) + COALESCE(sl.outQty, 0)), 0) AS totalQty |
|
|
COALESCE(SUM(COALESCE(sl.inQty, 0) + COALESCE(sl.outQty, 0)), 0) AS totalQty |
|
|
FROM stock_ledger sl |
|
|
|
|
|
|
|
|
FROM stock_ledger sl FORCE INDEX (idx_sl_deleted_date) |
|
|
WHERE sl.deleted = 0 AND sl.date IS NOT NULL |
|
|
WHERE sl.deleted = 0 AND sl.date IS NOT NULL |
|
|
$startSql $endSql |
|
|
|
|
|
GROUP BY sl.date |
|
|
|
|
|
ORDER BY sl.date |
|
|
|
|
|
|
|
|
$rangeSql |
|
|
|
|
|
GROUP BY DATE_FORMAT(sl.date, '%Y-%m-%d') |
|
|
|
|
|
ORDER BY date |
|
|
""".trimIndent() |
|
|
""".trimIndent() |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
} |
|
|
} |
|
|
@@ -45,14 +39,7 @@ open class ChartService( |
|
|
*/ |
|
|
*/ |
|
|
fun getDeliveryOrderByDate(startDate: LocalDate?, endDate: LocalDate?): List<Map<String, Any>> { |
|
|
fun getDeliveryOrderByDate(startDate: LocalDate?, endDate: LocalDate?): List<Map<String, Any>> { |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val startSql = if (startDate != null) { |
|
|
|
|
|
args["startDate"] = startDate.toString() |
|
|
|
|
|
"AND DATE(do.estimatedArrivalDate) >= :startDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
val endSql = if (endDate != null) { |
|
|
|
|
|
args["endDate"] = endDate.toString() |
|
|
|
|
|
"AND DATE(do.estimatedArrivalDate) <= :endDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
|
|
|
val rangeSql = localDateRangeSql(args, "do.estimatedArrivalDate", startDate, endDate) |
|
|
val sql = """ |
|
|
val sql = """ |
|
|
SELECT |
|
|
SELECT |
|
|
DATE_FORMAT(do.estimatedArrivalDate, '%Y-%m-%d') AS date, |
|
|
DATE_FORMAT(do.estimatedArrivalDate, '%Y-%m-%d') AS date, |
|
|
@@ -60,8 +47,9 @@ open class ChartService( |
|
|
COALESCE(SUM(dol.qty), 0) AS totalQty |
|
|
COALESCE(SUM(dol.qty), 0) AS totalQty |
|
|
FROM delivery_order do |
|
|
FROM delivery_order do |
|
|
LEFT JOIN delivery_order_line dol ON dol.deliveryOrderId = do.id AND dol.deleted = 0 |
|
|
LEFT JOIN delivery_order_line dol ON dol.deliveryOrderId = do.id AND dol.deleted = 0 |
|
|
WHERE do.deleted = 0 AND do.estimatedArrivalDate IS NOT NULL $startSql $endSql |
|
|
|
|
|
GROUP BY DATE(do.estimatedArrivalDate) |
|
|
|
|
|
|
|
|
WHERE do.deleted = 0 AND do.estimatedArrivalDate IS NOT NULL |
|
|
|
|
|
$rangeSql |
|
|
|
|
|
GROUP BY DATE_FORMAT(do.estimatedArrivalDate, '%Y-%m-%d') |
|
|
ORDER BY date |
|
|
ORDER BY date |
|
|
""".trimIndent() |
|
|
""".trimIndent() |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
@@ -536,46 +524,39 @@ open class ChartService( |
|
|
*/ |
|
|
*/ |
|
|
fun getStockInOutByDate(startDate: LocalDate?, endDate: LocalDate?): List<Map<String, Any>> { |
|
|
fun getStockInOutByDate(startDate: LocalDate?, endDate: LocalDate?): List<Map<String, Any>> { |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val args = mutableMapOf<String, Any>() |
|
|
if (startDate != null) args["startDate"] = startDate.toString() |
|
|
|
|
|
if (endDate != null) args["endDate"] = endDate.toString() |
|
|
|
|
|
val inDateFilter = buildString { |
|
|
|
|
|
if (startDate != null) { |
|
|
|
|
|
append(" AND DATE(COALESCE(si.completeDate, sil.receiptDate, si.created)) >= :startDate") |
|
|
|
|
|
} |
|
|
|
|
|
if (endDate != null) { |
|
|
|
|
|
append(" AND DATE(COALESCE(si.completeDate, sil.receiptDate, si.created)) <= :endDate") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
val outDateFilter = buildString { |
|
|
|
|
|
if (startDate != null) { |
|
|
|
|
|
append(" AND DATE(COALESCE(so.completeDate, so.created)) >= :startDate") |
|
|
|
|
|
} |
|
|
|
|
|
if (endDate != null) { |
|
|
|
|
|
append(" AND DATE(COALESCE(so.completeDate, so.created)) <= :endDate") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
val startSql = if (startDate != null) "AND u.dt >= :startDate" else "" |
|
|
|
|
|
val endSql = if (endDate != null) "AND u.dt <= :endDate" else "" |
|
|
|
|
|
|
|
|
val rangeStart = startDate?.atStartOfDay() |
|
|
|
|
|
val rangeEndExclusive = endDate?.plusDays(1)?.atStartOfDay() |
|
|
|
|
|
if (rangeStart != null) args["inOutRangeStart"] = rangeStart |
|
|
|
|
|
if (rangeEndExclusive != null) args["inOutRangeEndExclusive"] = rangeEndExclusive |
|
|
|
|
|
val inDateFilter = stockInOutCoalescedDateRangeSql( |
|
|
|
|
|
"COALESCE(si.completeDate, sil.receiptDate, si.created)", |
|
|
|
|
|
rangeStart, |
|
|
|
|
|
rangeEndExclusive, |
|
|
|
|
|
) |
|
|
|
|
|
val outDateFilter = stockInOutCoalescedDateRangeSql( |
|
|
|
|
|
"COALESCE(so.completeDate, so.created)", |
|
|
|
|
|
rangeStart, |
|
|
|
|
|
rangeEndExclusive, |
|
|
|
|
|
) |
|
|
val sql = """ |
|
|
val sql = """ |
|
|
SELECT DATE_FORMAT(u.dt, '%Y-%m-%d') AS date, |
|
|
|
|
|
|
|
|
SELECT u.dt AS date, |
|
|
COALESCE(SUM(u.inQty), 0) AS inQty, |
|
|
COALESCE(SUM(u.inQty), 0) AS inQty, |
|
|
COALESCE(SUM(u.outQty), 0) AS outQty |
|
|
COALESCE(SUM(u.outQty), 0) AS outQty |
|
|
FROM ( |
|
|
FROM ( |
|
|
SELECT DATE(COALESCE(si.completeDate, sil.receiptDate, si.created)) AS dt, |
|
|
|
|
|
|
|
|
SELECT DATE_FORMAT(COALESCE(si.completeDate, sil.receiptDate, si.created), '%Y-%m-%d') AS dt, |
|
|
SUM(COALESCE(sil.acceptedQty, 0)) AS inQty, 0 AS outQty |
|
|
SUM(COALESCE(sil.acceptedQty, 0)) AS inQty, 0 AS outQty |
|
|
FROM stock_in si |
|
|
FROM stock_in si |
|
|
STRAIGHT_JOIN stock_in_line sil ON sil.stockInId = si.id AND sil.deleted = 0 |
|
|
STRAIGHT_JOIN stock_in_line sil ON sil.stockInId = si.id AND sil.deleted = 0 |
|
|
WHERE si.deleted = 0$inDateFilter |
|
|
WHERE si.deleted = 0$inDateFilter |
|
|
GROUP BY DATE(COALESCE(si.completeDate, sil.receiptDate, si.created)) |
|
|
|
|
|
|
|
|
GROUP BY DATE_FORMAT(COALESCE(si.completeDate, sil.receiptDate, si.created), '%Y-%m-%d') |
|
|
UNION ALL |
|
|
UNION ALL |
|
|
SELECT DATE(COALESCE(so.completeDate, so.created)) AS dt, |
|
|
|
|
|
|
|
|
SELECT DATE_FORMAT(COALESCE(so.completeDate, so.created), '%Y-%m-%d') AS dt, |
|
|
0 AS inQty, SUM(COALESCE(sol.qty, 0)) AS outQty |
|
|
0 AS inQty, SUM(COALESCE(sol.qty, 0)) AS outQty |
|
|
FROM stock_out so |
|
|
FROM stock_out so |
|
|
STRAIGHT_JOIN stock_out_line sol ON sol.stockOutId = so.id AND sol.deleted = 0 |
|
|
STRAIGHT_JOIN stock_out_line sol ON sol.stockOutId = so.id AND sol.deleted = 0 |
|
|
WHERE so.deleted = 0$outDateFilter |
|
|
WHERE so.deleted = 0$outDateFilter |
|
|
GROUP BY DATE(COALESCE(so.completeDate, so.created)) |
|
|
|
|
|
|
|
|
GROUP BY DATE_FORMAT(COALESCE(so.completeDate, so.created), '%Y-%m-%d') |
|
|
) u |
|
|
) u |
|
|
WHERE 1=1 $startSql $endSql |
|
|
|
|
|
GROUP BY u.dt |
|
|
GROUP BY u.dt |
|
|
ORDER BY u.dt |
|
|
ORDER BY u.dt |
|
|
""".trimIndent() |
|
|
""".trimIndent() |
|
|
@@ -589,20 +570,14 @@ open class ChartService( |
|
|
*/ |
|
|
*/ |
|
|
fun getTopDeliveryItemsItemOptions(startDate: LocalDate?, endDate: LocalDate?): List<Map<String, Any>> { |
|
|
fun getTopDeliveryItemsItemOptions(startDate: LocalDate?, endDate: LocalDate?): List<Map<String, Any>> { |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val startSql = if (startDate != null) { |
|
|
|
|
|
args["startDate"] = startDate.toString() |
|
|
|
|
|
"AND DATE(do.estimatedArrivalDate) >= :startDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
val endSql = if (endDate != null) { |
|
|
|
|
|
args["endDate"] = endDate.toString() |
|
|
|
|
|
"AND DATE(do.estimatedArrivalDate) <= :endDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
|
|
|
val rangeSql = localDateRangeSql(args, "do.estimatedArrivalDate", startDate, endDate) |
|
|
val sql = """ |
|
|
val sql = """ |
|
|
SELECT DISTINCT it.code AS itemCode, COALESCE(it.name, '') AS itemName |
|
|
SELECT DISTINCT it.code AS itemCode, COALESCE(it.name, '') AS itemName |
|
|
FROM delivery_order do |
|
|
FROM delivery_order do |
|
|
STRAIGHT_JOIN delivery_order_line dol ON dol.deliveryOrderId = do.id AND dol.deleted = 0 |
|
|
STRAIGHT_JOIN delivery_order_line dol ON dol.deliveryOrderId = do.id AND dol.deleted = 0 |
|
|
STRAIGHT_JOIN items it ON it.id = dol.itemId AND it.deleted = 0 |
|
|
STRAIGHT_JOIN items it ON it.id = dol.itemId AND it.deleted = 0 |
|
|
WHERE do.deleted = 0 AND do.estimatedArrivalDate IS NOT NULL $startSql $endSql |
|
|
|
|
|
|
|
|
WHERE do.deleted = 0 AND do.estimatedArrivalDate IS NOT NULL |
|
|
|
|
|
$rangeSql |
|
|
ORDER BY it.code |
|
|
ORDER BY it.code |
|
|
""".trimIndent() |
|
|
""".trimIndent() |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
@@ -620,14 +595,7 @@ open class ChartService( |
|
|
itemCodes: List<String>? |
|
|
itemCodes: List<String>? |
|
|
): List<Map<String, Any>> { |
|
|
): List<Map<String, Any>> { |
|
|
val args = mutableMapOf<String, Any>("limit" to limit) |
|
|
val args = mutableMapOf<String, Any>("limit" to limit) |
|
|
val startSql = if (startDate != null) { |
|
|
|
|
|
args["startDate"] = startDate.toString() |
|
|
|
|
|
"AND DATE(do.estimatedArrivalDate) >= :startDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
val endSql = if (endDate != null) { |
|
|
|
|
|
args["endDate"] = endDate.toString() |
|
|
|
|
|
"AND DATE(do.estimatedArrivalDate) <= :endDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
|
|
|
val rangeSql = localDateRangeSql(args, "do.estimatedArrivalDate", startDate, endDate) |
|
|
val itemSql = if (!itemCodes.isNullOrEmpty()) { |
|
|
val itemSql = if (!itemCodes.isNullOrEmpty()) { |
|
|
val codes = itemCodes.map { it.trim() }.filter { it.isNotBlank() } |
|
|
val codes = itemCodes.map { it.trim() }.filter { it.isNotBlank() } |
|
|
if (codes.isEmpty()) "" else { |
|
|
if (codes.isEmpty()) "" else { |
|
|
@@ -643,7 +611,8 @@ open class ChartService( |
|
|
FROM delivery_order do |
|
|
FROM delivery_order do |
|
|
STRAIGHT_JOIN delivery_order_line dol ON dol.deliveryOrderId = do.id AND dol.deleted = 0 |
|
|
STRAIGHT_JOIN delivery_order_line dol ON dol.deliveryOrderId = do.id AND dol.deleted = 0 |
|
|
STRAIGHT_JOIN items it ON it.id = dol.itemId AND it.deleted = 0 |
|
|
STRAIGHT_JOIN items it ON it.id = dol.itemId AND it.deleted = 0 |
|
|
WHERE do.deleted = 0 AND do.estimatedArrivalDate IS NOT NULL $startSql $endSql $itemSql |
|
|
|
|
|
|
|
|
WHERE do.deleted = 0 AND do.estimatedArrivalDate IS NOT NULL |
|
|
|
|
|
$rangeSql $itemSql |
|
|
GROUP BY dol.itemId, it.code, it.name |
|
|
GROUP BY dol.itemId, it.code, it.name |
|
|
ORDER BY totalQty DESC |
|
|
ORDER BY totalQty DESC |
|
|
LIMIT :limit |
|
|
LIMIT :limit |
|
|
@@ -661,26 +630,26 @@ open class ChartService( |
|
|
itemCode: String? |
|
|
itemCode: String? |
|
|
): List<Map<String, Any>> { |
|
|
): List<Map<String, Any>> { |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val startSql = if (startDate != null) { |
|
|
|
|
|
args["startDate"] = startDate.toString() |
|
|
|
|
|
"AND sl.date >= :startDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
val endSql = if (endDate != null) { |
|
|
|
|
|
args["endDate"] = endDate.toString() |
|
|
|
|
|
"AND sl.date <= :endDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
val itemSql = if (!itemCode.isNullOrBlank()) { |
|
|
|
|
|
|
|
|
val rangeSql = ledgerDateTimeRangeSql(args, "sl.date", startDate, endDate) |
|
|
|
|
|
val hasItemFilter = !itemCode.isNullOrBlank() |
|
|
|
|
|
if (hasItemFilter) { |
|
|
args["itemCode"] = "%$itemCode%" |
|
|
args["itemCode"] = "%$itemCode%" |
|
|
"AND sl.itemCode LIKE :itemCode" |
|
|
|
|
|
} else "" |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
val itemSql = if (hasItemFilter) "AND sl.itemCode LIKE :itemCode" else "" |
|
|
|
|
|
val fromClause = if (hasItemFilter) { |
|
|
|
|
|
"FROM stock_ledger sl" |
|
|
|
|
|
} else { |
|
|
|
|
|
"FROM stock_ledger sl FORCE INDEX (idx_sl_deleted_date)" |
|
|
|
|
|
} |
|
|
val sql = """ |
|
|
val sql = """ |
|
|
SELECT |
|
|
SELECT |
|
|
DATE_FORMAT(sl.date, '%Y-%m-%d') AS date, |
|
|
DATE_FORMAT(sl.date, '%Y-%m-%d') AS date, |
|
|
COALESCE(SUM(sl.balance), 0) AS balance |
|
|
COALESCE(SUM(sl.balance), 0) AS balance |
|
|
FROM stock_ledger sl |
|
|
|
|
|
WHERE sl.deleted = 0 AND sl.date IS NOT NULL $startSql $endSql $itemSql |
|
|
|
|
|
GROUP BY sl.date |
|
|
|
|
|
ORDER BY sl.date |
|
|
|
|
|
|
|
|
$fromClause |
|
|
|
|
|
WHERE sl.deleted = 0 AND sl.date IS NOT NULL |
|
|
|
|
|
$rangeSql $itemSql |
|
|
|
|
|
GROUP BY DATE_FORMAT(sl.date, '%Y-%m-%d') |
|
|
|
|
|
ORDER BY date |
|
|
""".trimIndent() |
|
|
""".trimIndent() |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
} |
|
|
} |
|
|
@@ -697,27 +666,35 @@ open class ChartService( |
|
|
): List<Map<String, Any>> { |
|
|
): List<Map<String, Any>> { |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val yearSql = if (year != null) { |
|
|
val yearSql = if (year != null) { |
|
|
args["year"] = year |
|
|
|
|
|
"AND YEAR(sl.date) = :year" |
|
|
|
|
|
} else "" |
|
|
|
|
|
val startSql = if (startDate != null) { |
|
|
|
|
|
args["startDate"] = startDate.toString() |
|
|
|
|
|
"AND sl.date >= :startDate" |
|
|
|
|
|
} else "" |
|
|
|
|
|
val endSql = if (endDate != null) { |
|
|
|
|
|
args["endDate"] = endDate.toString() |
|
|
|
|
|
"AND sl.date <= :endDate" |
|
|
|
|
|
|
|
|
args["consumptionYearStart"] = LocalDate.of(year, 1, 1).atStartOfDay() |
|
|
|
|
|
args["consumptionYearEndExclusive"] = LocalDate.of(year + 1, 1, 1).atStartOfDay() |
|
|
|
|
|
"AND sl.date >= :consumptionYearStart AND sl.date < :consumptionYearEndExclusive" |
|
|
} else "" |
|
|
} else "" |
|
|
val itemSql = if (!itemCode.isNullOrBlank()) { |
|
|
|
|
|
|
|
|
val rangeSql = ledgerDateTimeRangeSql( |
|
|
|
|
|
args, |
|
|
|
|
|
"sl.date", |
|
|
|
|
|
startDate, |
|
|
|
|
|
endDate, |
|
|
|
|
|
startArg = "consumptionRangeStart", |
|
|
|
|
|
endArg = "consumptionRangeEndExclusive", |
|
|
|
|
|
) |
|
|
|
|
|
val hasItemFilter = !itemCode.isNullOrBlank() |
|
|
|
|
|
if (hasItemFilter) { |
|
|
args["itemCode"] = "%$itemCode%" |
|
|
args["itemCode"] = "%$itemCode%" |
|
|
"AND sl.itemCode LIKE :itemCode" |
|
|
|
|
|
} else "" |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
val itemSql = if (hasItemFilter) "AND sl.itemCode LIKE :itemCode" else "" |
|
|
|
|
|
val fromClause = if (hasItemFilter) { |
|
|
|
|
|
"FROM stock_ledger sl" |
|
|
|
|
|
} else { |
|
|
|
|
|
"FROM stock_ledger sl FORCE INDEX (idx_sl_deleted_date)" |
|
|
|
|
|
} |
|
|
val sql = """ |
|
|
val sql = """ |
|
|
SELECT |
|
|
SELECT |
|
|
DATE_FORMAT(sl.date, '%Y-%m') AS month, |
|
|
DATE_FORMAT(sl.date, '%Y-%m') AS month, |
|
|
COALESCE(SUM(sl.outQty), 0) AS outQty |
|
|
COALESCE(SUM(sl.outQty), 0) AS outQty |
|
|
FROM stock_ledger sl |
|
|
|
|
|
WHERE sl.deleted = 0 AND sl.date IS NOT NULL $yearSql $startSql $endSql $itemSql |
|
|
|
|
|
|
|
|
$fromClause |
|
|
|
|
|
WHERE sl.deleted = 0 AND sl.date IS NOT NULL |
|
|
|
|
|
$yearSql $rangeSql $itemSql |
|
|
GROUP BY DATE_FORMAT(sl.date, '%Y-%m') |
|
|
GROUP BY DATE_FORMAT(sl.date, '%Y-%m') |
|
|
ORDER BY month |
|
|
ORDER BY month |
|
|
""".trimIndent() |
|
|
""".trimIndent() |
|
|
@@ -746,6 +723,8 @@ open class ChartService( |
|
|
* staffNos: when non-empty, filter to these staff by user.staffNo (multi-select). |
|
|
* staffNos: when non-empty, filter to these staff by user.staffNo (multi-select). |
|
|
* storeIdNull: when true, only rows with dop.storeId IS NULL (takes precedence over storeId). |
|
|
* storeIdNull: when true, only rows with dop.storeId IS NULL (takes precedence over storeId). |
|
|
* storeId: when non-blank and storeIdNull is not true, filter dop.storeId equality (trimmed). |
|
|
* storeId: when non-blank and storeIdNull is not true, filter dop.storeId equality (trimmed). |
|
|
|
|
|
* When no store filter, FORCE INDEX (idx_dopo_staff_perf_complete) so the optimizer uses a |
|
|
|
|
|
* ticketCompleteDateTime range scan instead of a less selective store composite index. |
|
|
*/ |
|
|
*/ |
|
|
fun getStaffDeliveryPerformance( |
|
|
fun getStaffDeliveryPerformance( |
|
|
startDate: LocalDate?, |
|
|
startDate: LocalDate?, |
|
|
@@ -756,12 +735,12 @@ open class ChartService( |
|
|
): List<Map<String, Any>> { |
|
|
): List<Map<String, Any>> { |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val args = mutableMapOf<String, Any>() |
|
|
val startSql = if (startDate != null) { |
|
|
val startSql = if (startDate != null) { |
|
|
args["startDate"] = startDate.toString() |
|
|
|
|
|
"AND DATE(dop.ticketCompleteDateTime) >= :startDate" |
|
|
|
|
|
|
|
|
args["startDate"] = startDate.atStartOfDay() |
|
|
|
|
|
"AND dop.ticketCompleteDateTime >= :startDate" |
|
|
} else "" |
|
|
} else "" |
|
|
val endSql = if (endDate != null) { |
|
|
val endSql = if (endDate != null) { |
|
|
args["endDate"] = endDate.toString() |
|
|
|
|
|
"AND DATE(dop.ticketCompleteDateTime) <= :endDate" |
|
|
|
|
|
|
|
|
args["endExclusive"] = endDate.plusDays(1).atStartOfDay() |
|
|
|
|
|
"AND dop.ticketCompleteDateTime < :endExclusive" |
|
|
} else "" |
|
|
} else "" |
|
|
val staffSql = if (!staffNos.isNullOrEmpty()) { |
|
|
val staffSql = if (!staffNos.isNullOrEmpty()) { |
|
|
val nos = staffNos.map { it.trim() }.filter { it.isNotBlank() } |
|
|
val nos = staffNos.map { it.trim() }.filter { it.isNotBlank() } |
|
|
@@ -778,6 +757,12 @@ open class ChartService( |
|
|
} |
|
|
} |
|
|
else -> "" |
|
|
else -> "" |
|
|
} |
|
|
} |
|
|
|
|
|
val useStoreFilter = storeIdNull == true || !storeId.isNullOrBlank() |
|
|
|
|
|
val fromClause = if (useStoreFilter) { |
|
|
|
|
|
"FROM delivery_order_pick_order dop" |
|
|
|
|
|
} else { |
|
|
|
|
|
"FROM delivery_order_pick_order dop FORCE INDEX (idx_dopo_staff_perf_complete)" |
|
|
|
|
|
} |
|
|
val sql = """ |
|
|
val sql = """ |
|
|
SELECT |
|
|
SELECT |
|
|
DATE_FORMAT(dop.ticketCompleteDateTime, '%Y-%m-%d') AS date, |
|
|
DATE_FORMAT(dop.ticketCompleteDateTime, '%Y-%m-%d') AS date, |
|
|
@@ -790,13 +775,14 @@ open class ChartService( |
|
|
ELSE 0 |
|
|
ELSE 0 |
|
|
END |
|
|
END |
|
|
), 0) AS totalMinutes |
|
|
), 0) AS totalMinutes |
|
|
FROM delivery_order_pick_order dop |
|
|
|
|
|
|
|
|
$fromClause |
|
|
LEFT JOIN user u ON dop.handledBy = u.id AND u.deleted = 0 |
|
|
LEFT JOIN user u ON dop.handledBy = u.id AND u.deleted = 0 |
|
|
WHERE dop.deleted = 0 |
|
|
WHERE dop.deleted = 0 |
|
|
AND LOWER(COALESCE(dop.ticketStatus, '')) = 'completed' |
|
|
|
|
|
|
|
|
AND dop.ticketStatus = 'completed' |
|
|
AND dop.ticketCompleteDateTime IS NOT NULL |
|
|
AND dop.ticketCompleteDateTime IS NOT NULL |
|
|
$startSql $endSql $staffSql $storeSql |
|
|
$startSql $endSql $staffSql $storeSql |
|
|
GROUP BY DATE(dop.ticketCompleteDateTime), dop.handledBy, u.name, dop.handlerName |
|
|
|
|
|
|
|
|
GROUP BY DATE_FORMAT(dop.ticketCompleteDateTime, '%Y-%m-%d'), |
|
|
|
|
|
dop.handledBy, u.name, dop.handlerName |
|
|
ORDER BY date, orderCount DESC |
|
|
ORDER BY date, orderCount DESC |
|
|
""".trimIndent() |
|
|
""".trimIndent() |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
@@ -1604,4 +1590,56 @@ open class ChartService( |
|
|
""".trimIndent() |
|
|
""".trimIndent() |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
return jdbcDao.queryForList(sql, args) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Half-open [start, end+1 day) on a DATE/DATETIME column (no DATE() wrapper). */ |
|
|
|
|
|
private fun localDateRangeSql( |
|
|
|
|
|
args: MutableMap<String, Any>, |
|
|
|
|
|
column: String, |
|
|
|
|
|
startDate: LocalDate?, |
|
|
|
|
|
endDate: LocalDate?, |
|
|
|
|
|
startArg: String = "chartRangeStart", |
|
|
|
|
|
endArg: String = "chartRangeEndExclusive", |
|
|
|
|
|
): String = buildString { |
|
|
|
|
|
if (startDate != null) { |
|
|
|
|
|
args[startArg] = startDate |
|
|
|
|
|
append(" AND $column >= :$startArg") |
|
|
|
|
|
} |
|
|
|
|
|
if (endDate != null) { |
|
|
|
|
|
args[endArg] = endDate.plusDays(1) |
|
|
|
|
|
append(" AND $column < :$endArg") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** Half-open range on stock_ledger.date (DATETIME). */ |
|
|
|
|
|
private fun ledgerDateTimeRangeSql( |
|
|
|
|
|
args: MutableMap<String, Any>, |
|
|
|
|
|
column: String, |
|
|
|
|
|
startDate: LocalDate?, |
|
|
|
|
|
endDate: LocalDate?, |
|
|
|
|
|
startArg: String = "ledgerRangeStart", |
|
|
|
|
|
endArg: String = "ledgerRangeEndExclusive", |
|
|
|
|
|
): String = buildString { |
|
|
|
|
|
if (startDate != null) { |
|
|
|
|
|
args[startArg] = startDate.atStartOfDay() |
|
|
|
|
|
append(" AND $column >= :$startArg") |
|
|
|
|
|
} |
|
|
|
|
|
if (endDate != null) { |
|
|
|
|
|
args[endArg] = endDate.plusDays(1).atStartOfDay() |
|
|
|
|
|
append(" AND $column < :$endArg") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** COALESCE datetime expression; args [inOutRangeStart] / [inOutRangeEndExclusive] must already be in map when non-null. */ |
|
|
|
|
|
private fun stockInOutCoalescedDateRangeSql( |
|
|
|
|
|
coalescedExpr: String, |
|
|
|
|
|
rangeStart: LocalDateTime?, |
|
|
|
|
|
rangeEndExclusive: LocalDateTime?, |
|
|
|
|
|
): String = buildString { |
|
|
|
|
|
if (rangeStart != null) { |
|
|
|
|
|
append(" AND $coalescedExpr >= :inOutRangeStart") |
|
|
|
|
|
} |
|
|
|
|
|
if (rangeEndExclusive != null) { |
|
|
|
|
|
append(" AND $coalescedExpr < :inOutRangeEndExclusive") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |