ソースを参照

chart sql improt

production
CANCERYS\kw093 1ヶ月前
コミット
7141c0f6b4
2個のファイルの変更56行の追加34行の削除
  1. +52
    -32
      src/main/java/com/ffii/fpsms/modules/chart/service/ChartService.kt
  2. +4
    -2
      src/main/java/com/ffii/fpsms/modules/chart/web/ChartController.kt

+ 52
- 32
src/main/java/com/ffii/fpsms/modules/chart/service/ChartService.kt ファイルの表示

@@ -40,27 +40,28 @@ open class ChartService(


/** /**
* Delivery orders: order count and total line qty by date. * Delivery orders: order count and total line qty by date.
* Uses delivery_order.completeDate or estimatedArrivalDate for date.
* X-axis date: [delivery_order.estimatedArrivalDate] only (no completeDate/orderDate fallback).
* Rows without estimatedArrivalDate are excluded.
*/ */
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) { val startSql = if (startDate != null) {
args["startDate"] = startDate.toString() args["startDate"] = startDate.toString()
"AND DATE(COALESCE(do.completeDate, do.estimatedArrivalDate, do.orderDate)) >= :startDate"
"AND DATE(do.estimatedArrivalDate) >= :startDate"
} else "" } else ""
val endSql = if (endDate != null) { val endSql = if (endDate != null) {
args["endDate"] = endDate.toString() args["endDate"] = endDate.toString()
"AND DATE(COALESCE(do.completeDate, do.estimatedArrivalDate, do.orderDate)) <= :endDate"
"AND DATE(do.estimatedArrivalDate) <= :endDate"
} else "" } else ""
val sql = """ val sql = """
SELECT SELECT
DATE_FORMAT(COALESCE(do.completeDate, do.estimatedArrivalDate, do.orderDate), '%Y-%m-%d') AS date,
DATE_FORMAT(do.estimatedArrivalDate, '%Y-%m-%d') AS date,
COUNT(DISTINCT do.id) AS orderCount, COUNT(DISTINCT do.id) AS orderCount,
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 $startSql $endSql
GROUP BY DATE(COALESCE(do.completeDate, do.estimatedArrivalDate, do.orderDate))
WHERE do.deleted = 0 AND do.estimatedArrivalDate IS NOT NULL $startSql $endSql
GROUP BY DATE(do.estimatedArrivalDate)
ORDER BY date ORDER BY date
""".trimIndent() """.trimIndent()
return jdbcDao.queryForList(sql, args) return jdbcDao.queryForList(sql, args)
@@ -529,17 +530,32 @@ open class ChartService(
* Stock in vs stock out by date. * Stock in vs stock out by date.
* Stock in: stock_in_line.acceptedQty, date from stock_in.completeDate or receiptDate/created. * Stock in: stock_in_line.acceptedQty, date from stock_in.completeDate or receiptDate/created.
* Stock out: stock_out_line.qty, date from stock_out.completeDate or created. * Stock out: stock_out_line.qty, date from stock_out.completeDate or created.
*
* Date range is applied inside each UNION branch (predicate pushdown) so we do not aggregate
* all history before filtering. Reads filtered headers first via STRAIGHT_JOIN (si/so then lines).
*/ */
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>()
val startSql = if (startDate != null) {
args["startDate"] = startDate.toString()
"AND u.dt >= :startDate"
} else ""
val endSql = if (endDate != null) {
args["endDate"] = endDate.toString()
"AND u.dt <= :endDate"
} else ""
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 sql = """ val sql = """
SELECT DATE_FORMAT(u.dt, '%Y-%m-%d') AS date, SELECT DATE_FORMAT(u.dt, '%Y-%m-%d') AS date,
COALESCE(SUM(u.inQty), 0) AS inQty, COALESCE(SUM(u.inQty), 0) AS inQty,
@@ -547,16 +563,16 @@ open class ChartService(
FROM ( FROM (
SELECT DATE(COALESCE(si.completeDate, sil.receiptDate, si.created)) AS dt, SELECT DATE(COALESCE(si.completeDate, sil.receiptDate, si.created)) 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_line sil
INNER JOIN stock_in si ON sil.stockInId = si.id AND si.deleted = 0
WHERE sil.deleted = 0
FROM stock_in si
STRAIGHT_JOIN stock_in_line sil ON sil.stockInId = si.id AND sil.deleted = 0
WHERE si.deleted = 0$inDateFilter
GROUP BY DATE(COALESCE(si.completeDate, sil.receiptDate, si.created)) GROUP BY DATE(COALESCE(si.completeDate, sil.receiptDate, si.created))
UNION ALL UNION ALL
SELECT DATE(COALESCE(so.completeDate, so.created)) AS dt, SELECT DATE(COALESCE(so.completeDate, so.created)) 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_line sol
INNER JOIN stock_out so ON sol.stockOutId = so.id AND so.deleted = 0
WHERE sol.deleted = 0
FROM stock_out so
STRAIGHT_JOIN stock_out_line sol ON sol.stockOutId = so.id AND sol.deleted = 0
WHERE so.deleted = 0$outDateFilter
GROUP BY DATE(COALESCE(so.completeDate, so.created)) GROUP BY DATE(COALESCE(so.completeDate, so.created))
) u ) u
WHERE 1=1 $startSql $endSql WHERE 1=1 $startSql $endSql
@@ -568,23 +584,25 @@ open class ChartService(


/** /**
* Distinct items that appear in delivery_order_line in the period (for multi-select options). * Distinct items that appear in delivery_order_line in the period (for multi-select options).
* Period filter: [delivery_order.estimatedArrivalDate] only; null ETA excluded.
* Uses STRAIGHT_JOIN so MySQL reads filtered `delivery_order` first (avoids full scan on `delivery_order_line`).
*/ */
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) { val startSql = if (startDate != null) {
args["startDate"] = startDate.toString() args["startDate"] = startDate.toString()
"AND DATE(COALESCE(do.completeDate, do.estimatedArrivalDate, do.orderDate)) >= :startDate"
"AND DATE(do.estimatedArrivalDate) >= :startDate"
} else "" } else ""
val endSql = if (endDate != null) { val endSql = if (endDate != null) {
args["endDate"] = endDate.toString() args["endDate"] = endDate.toString()
"AND DATE(COALESCE(do.completeDate, do.estimatedArrivalDate, do.orderDate)) <= :endDate"
"AND DATE(do.estimatedArrivalDate) <= :endDate"
} else "" } else ""
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_line dol
INNER JOIN delivery_order do ON dol.deliveryOrderId = do.id AND do.deleted = 0
INNER JOIN items it ON dol.itemId = it.id AND it.deleted = 0
WHERE dol.deleted = 0 $startSql $endSql
FROM delivery_order do
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
WHERE do.deleted = 0 AND do.estimatedArrivalDate IS NOT NULL $startSql $endSql
ORDER BY it.code ORDER BY it.code
""".trimIndent() """.trimIndent()
return jdbcDao.queryForList(sql, args) return jdbcDao.queryForList(sql, args)
@@ -592,6 +610,8 @@ open class ChartService(


/** /**
* Top delivery items by total qty in the period. When itemCodes is non-empty, only those items (still ordered by totalQty, limit applied). * Top delivery items by total qty in the period. When itemCodes is non-empty, only those items (still ordered by totalQty, limit applied).
* Period filter: [delivery_order.estimatedArrivalDate] only; null ETA excluded.
* Uses STRAIGHT_JOIN so MySQL reads filtered `delivery_order` first (avoids full scan on `delivery_order_line`).
*/ */
fun getTopDeliveryItems( fun getTopDeliveryItems(
startDate: LocalDate?, startDate: LocalDate?,
@@ -602,11 +622,11 @@ open class ChartService(
val args = mutableMapOf<String, Any>("limit" to limit) val args = mutableMapOf<String, Any>("limit" to limit)
val startSql = if (startDate != null) { val startSql = if (startDate != null) {
args["startDate"] = startDate.toString() args["startDate"] = startDate.toString()
"AND DATE(COALESCE(do.completeDate, do.estimatedArrivalDate, do.orderDate)) >= :startDate"
"AND DATE(do.estimatedArrivalDate) >= :startDate"
} else "" } else ""
val endSql = if (endDate != null) { val endSql = if (endDate != null) {
args["endDate"] = endDate.toString() args["endDate"] = endDate.toString()
"AND DATE(COALESCE(do.completeDate, do.estimatedArrivalDate, do.orderDate)) <= :endDate"
"AND DATE(do.estimatedArrivalDate) <= :endDate"
} else "" } else ""
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() }
@@ -620,10 +640,10 @@ open class ChartService(
it.code AS itemCode, it.code AS itemCode,
it.name AS itemName, it.name AS itemName,
SUM(COALESCE(dol.qty, 0)) AS totalQty SUM(COALESCE(dol.qty, 0)) AS totalQty
FROM delivery_order_line dol
INNER JOIN delivery_order do ON dol.deliveryOrderId = do.id AND do.deleted = 0
INNER JOIN items it ON dol.itemId = it.id AND it.deleted = 0
WHERE dol.deleted = 0 $startSql $endSql $itemSql
FROM delivery_order do
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
WHERE do.deleted = 0 AND do.estimatedArrivalDate IS NOT NULL $startSql $endSql $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


+ 4
- 2
src/main/java/com/ffii/fpsms/modules/chart/web/ChartController.kt ファイルの表示

@@ -26,7 +26,7 @@ class ChartController(


/** /**
* GET /chart/delivery-order-by-date?startDate=&endDate= * GET /chart/delivery-order-by-date?startDate=&endDate=
* Returns [{ date, orderCount, totalQty }]
* Returns [{ date, orderCount, totalQty }]. Date axis: delivery_order.estimatedArrivalDate only (null ETA excluded).
*/ */
@GetMapping("/delivery-order-by-date") @GetMapping("/delivery-order-by-date")
fun getDeliveryOrderByDate( fun getDeliveryOrderByDate(
@@ -129,7 +129,7 @@ class ChartController(


/** /**
* GET /chart/stock-in-out-by-date?startDate=&endDate= * GET /chart/stock-in-out-by-date?startDate=&endDate=
* Returns [{ date, inQty, outQty }]
* Returns [{ date, inQty, outQty }]. Date range pushed into each UNION branch; si/so read before lines.
*/ */
@GetMapping("/stock-in-out-by-date") @GetMapping("/stock-in-out-by-date")
fun getStockInOutByDate( fun getStockInOutByDate(
@@ -140,6 +140,7 @@ class ChartController(
/** /**
* GET /chart/top-delivery-items-item-options?startDate=&endDate= * GET /chart/top-delivery-items-item-options?startDate=&endDate=
* Returns [{ itemCode, itemName }] — distinct items in delivery lines in the period (for multi-select). * Returns [{ itemCode, itemName }] — distinct items in delivery lines in the period (for multi-select).
* Period: delivery_order.estimatedArrivalDate only (null ETA excluded).
*/ */
@GetMapping("/top-delivery-items-item-options") @GetMapping("/top-delivery-items-item-options")
fun getTopDeliveryItemsItemOptions( fun getTopDeliveryItemsItemOptions(
@@ -150,6 +151,7 @@ class ChartController(
/** /**
* GET /chart/top-delivery-items?startDate=&endDate=&limit=20&itemCode=A&itemCode=B * GET /chart/top-delivery-items?startDate=&endDate=&limit=20&itemCode=A&itemCode=B
* Returns [{ itemCode, itemName, totalQty }]. When itemCode present, only those items (still by totalQty, limit). * Returns [{ itemCode, itemName, totalQty }]. When itemCode present, only those items (still by totalQty, limit).
* Period: delivery_order.estimatedArrivalDate only (null ETA excluded).
*/ */
@GetMapping("/top-delivery-items") @GetMapping("/top-delivery-items")
fun getTopDeliveryItems( fun getTopDeliveryItems(


読み込み中…
キャンセル
保存