Sfoglia il codice sorgente

Fix purchase order crash, add demo trucks

debrand
Harry Groves 1 mese fa
parent
commit
90f833aedb
5 ha cambiato i file con 243 aggiunte e 7 eliminazioni
  1. +232
    -0
      src/main/java/com/ffii/fpsms/modules/common/demo/DemoSandboxSeeder.kt
  2. +5
    -1
      src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt
  3. +3
    -3
      src/main/java/com/ffii/fpsms/modules/purchaseOrder/entity/projections/PurchaseOrderInfo.kt
  4. +2
    -2
      src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderService.kt
  5. +1
    -1
      src/main/java/com/ffii/fpsms/modules/purchaseOrder/web/PurchaseOrderController.kt

+ 232
- 0
src/main/java/com/ffii/fpsms/modules/common/demo/DemoSandboxSeeder.kt Vedi File

@@ -139,10 +139,13 @@ class DemoSandboxSeeder(
val existing = userRepository.findByUsernameAndDeletedFalse(DEMO_USERNAME)
if (existing.isPresent) {
assignDemoAuthorities(existing.get().id)
backfillDemoPurchaseLinePrices()
seedDashboardTrucks()
log.info("Demo sandbox already present (user '{}').", DEMO_USERNAME)
return@executeWithoutResult
}
seed()
seedDashboardTrucks()
log.info("Demo sandbox seeded. Sign in as {} / {}", DEMO_USERNAME, DEMO_PASSWORD)
}
}
@@ -171,6 +174,233 @@ class DemoSandboxSeeder(
throw IllegalStateException("Demo database login can read the live schema. Refusing to start.")
}

/**
* Truck board reads delivery_order_pick_order for today, tomorrow, and the day after.
* If those rows are still on an earlier day, shift them to the current date.
* Opening the dashboard does this, so a demo on a later day still has trucks to show.
*/
@Synchronized
fun alignDashboardTrucksToToday() {
val anchored = jdbcTemplate.query(
"""
SELECT requiredDeliveryDate
FROM delivery_order_pick_order
WHERE ticketNo = 'DEMO-DASH-0-2F-AM-A' AND deleted = 0
LIMIT 1
""".trimIndent(),
) { rs, _ -> rs.getDate("requiredDeliveryDate")?.toLocalDate() }.firstOrNull()
if (anchored == LocalDate.now()) return
seedDashboardTrucks()
}

private fun seedDashboardTrucks() {
val loafId = demoItemId("DEMO-FG-01")
val bunId = demoItemId("DEMO-FG-02")
val pcsId = jdbcTemplate.query(
"SELECT id FROM uom_conversion WHERE code = 'PCS' AND deleted = 0 ORDER BY id LIMIT 1",
) { rs, _ -> rs.getLong("id") }.firstOrNull()

for (truck in dashboardTrucks()) {
val inserted = jdbcTemplate.update(
"""
INSERT INTO delivery_order_pick_order (
storeId, requiredDeliveryDate, truckDepartureTime, truckLanceCode,
shopCode, shopName, loadingSequence, ticketNo, ticketStatus,
handlerName, createdBy, modifiedBy, deleted
)
SELECT ?, DATE_ADD(CURDATE(), INTERVAL ? DAY), ?, ?, ?, ?, ?, ?, ?, '示範倉務', 'demo', 'demo', 0
FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM delivery_order_pick_order WHERE ticketNo = ?
)
""".trimIndent(),
truck.storeId,
truck.dayOffset,
truck.departure,
truck.lane,
truck.shopCode,
truck.shopName,
truck.sequence,
truck.ticketNo,
truck.status,
truck.ticketNo,
)
jdbcTemplate.update(
"""
UPDATE delivery_order_pick_order
SET storeId = ?,
requiredDeliveryDate = DATE_ADD(CURDATE(), INTERVAL ? DAY),
truckDepartureTime = ?,
truckLanceCode = ?,
shopCode = ?,
shopName = ?,
loadingSequence = ?,
ticketStatus = ?,
handlerName = '示範倉務',
ticketReleaseTime = CASE
WHEN ? = 'pending' THEN NULL
ELSE TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL ? DAY), ?)
END,
ticketCompleteDateTime = CASE
WHEN ? = 'completed' THEN TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL ? DAY), ?)
ELSE NULL
END,
deleted = 0
WHERE ticketNo = ?
""".trimIndent(),
truck.storeId,
truck.dayOffset,
truck.departure,
truck.lane,
truck.shopCode,
truck.shopName,
truck.sequence,
truck.status,
truck.status,
truck.dayOffset,
truck.releaseTime,
truck.status,
truck.dayOffset,
truck.completeTime,
truck.ticketNo,
)
jdbcTemplate.update(
"""
INSERT INTO truck (
TruckLanceCode, DepartureTime, ShopCode, ShopName, LoadingSequence,
Store_id, districtReference, remark, deleted
)
SELECT ?, ?, ?, ?, ?, ?, '示範區', '示範車線', 0
FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM truck
WHERE deleted = 0
AND TruckLanceCode = ?
AND Store_id = ?
AND DepartureTime = ?
)
""".trimIndent(),
truck.lane,
truck.departure,
truck.shopCode,
truck.shopName,
truck.sequence,
truck.storeId,
truck.lane,
truck.storeId,
truck.departure,
)
if (loafId != null && bunId != null && pcsId != null) {
seedDashboardPickLines(truck, loafId, bunId, pcsId)
}
if (inserted > 0) {
log.info("Added demo truck ticket {}.", truck.ticketNo)
}
}
}

private fun seedDashboardPickLines(truck: DemoDashTruck, loafId: Long, bunId: Long, pcsId: Long) {
val pickCode = "DEMO-DASH-PK-${truck.ticketNo}"
jdbcTemplate.update(
"""
INSERT INTO pick_order (code, status, type, targetDate, deliveryOrderPickOrderId, deleted)
SELECT ?, 'released', 'do', TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL ? DAY), ?), d.id, 0
FROM delivery_order_pick_order d
WHERE d.ticketNo = ?
AND NOT EXISTS (SELECT 1 FROM pick_order p WHERE p.code = ?)
""".trimIndent(),
pickCode,
truck.dayOffset,
truck.departure,
truck.ticketNo,
pickCode,
)
jdbcTemplate.update(
"""
UPDATE pick_order p
JOIN delivery_order_pick_order d ON d.ticketNo = ?
SET p.deliveryOrderPickOrderId = d.id,
p.targetDate = TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL ? DAY), ?),
p.deleted = 0
WHERE p.code = ?
""".trimIndent(),
truck.ticketNo,
truck.dayOffset,
truck.departure,
pickCode,
)
for ((itemId, qty) in listOf(loafId to "6", bunId to "4")) {
jdbcTemplate.update(
"""
INSERT INTO pick_order_line (poId, itemId, qty, uomId, status, deleted)
SELECT p.id, ?, ?, ?, 'pending', 0
FROM pick_order p
WHERE p.code = ?
AND NOT EXISTS (
SELECT 1 FROM pick_order_line l
WHERE l.poId = p.id AND l.itemId = ? AND l.deleted = 0
)
""".trimIndent(),
itemId,
qty,
pcsId,
pickCode,
itemId,
)
}
}

private fun demoItemId(code: String): Long? {
return jdbcTemplate.query(
"SELECT id FROM items WHERE code = ? AND deleted = 0 ORDER BY id LIMIT 1",
{ rs, _ -> rs.getLong("id") },
code,
).firstOrNull()
}

private fun dashboardTrucks(): List<DemoDashTruck> = listOf(
DemoDashTruck("DEMO-DASH-0-2F-AM-A", 0, "2/F", "示範-早班", "08:30:00", "DEMO-SHP", "海港咖啡店", 1, "completed", "07:10:00", "07:48:00"),
DemoDashTruck("DEMO-DASH-0-2F-AM-B", 0, "2/F", "示範-早班", "08:30:00", "DEMO-BAK", "山景餅店", 2, "completed", "07:20:00", "07:55:00"),
DemoDashTruck("DEMO-DASH-0-2F-PM-A", 0, "2/F", "示範-午班", "14:30:00", "DEMO-BAY", "灣畔餐廳", 1, "released", "12:05:00", null),
DemoDashTruck("DEMO-DASH-0-2F-PM-B", 0, "2/F", "示範-午班", "14:30:00", "DEMO-CAMP", "校園小食", 2, "pending", null, null),
DemoDashTruck("DEMO-DASH-0-4F-PM-A", 0, "4/F", "示範-晚班", "17:00:00", "DEMO-SHP", "海港咖啡店", 1, "pending", null, null),
DemoDashTruck("DEMO-DASH-1-2F-AM-A", 1, "2/F", "示範-早班", "09:00:00", "DEMO-SHP", "海港咖啡店", 1, "pending", null, null),
DemoDashTruck("DEMO-DASH-1-2F-AM-B", 1, "2/F", "示範-早班", "09:00:00", "DEMO-BAK", "山景餅店", 2, "pending", null, null),
DemoDashTruck("DEMO-DASH-1-4F-NOON-A", 1, "4/F", "示範-午班", "13:30:00", "DEMO-BAY", "灣畔餐廳", 1, "pending", null, null),
DemoDashTruck("DEMO-DASH-2-2F-AM-A", 2, "2/F", "示範-早班", "09:15:00", "DEMO-SHP", "海港咖啡店", 1, "pending", null, null),
DemoDashTruck("DEMO-DASH-2-4F-EVE-A", 2, "4/F", "示範-晚班", "16:00:00", "DEMO-CAMP", "校園小食", 1, "pending", null, null),
)

private data class DemoDashTruck(
val ticketNo: String,
val dayOffset: Int,
val storeId: String,
val lane: String,
val departure: String,
val shopCode: String,
val shopName: String,
val sequence: Int,
val status: String,
val releaseTime: String?,
val completeTime: String?,
)

/** Existing sandboxes were seeded without a unit price, which made PO detail fail. */
private fun backfillDemoPurchaseLinePrices() {
val updated = jdbcTemplate.update(
"""
UPDATE purchase_order_line pol
INNER JOIN purchase_order po ON po.id = pol.purchaseOrderId
SET pol.price = 12.50, pol.up = 12.50
WHERE po.code LIKE 'DEMO-PO-%'
AND (pol.price IS NULL OR pol.up IS NULL)
""".trimIndent(),
)
if (updated > 0) {
log.info("Filled unit price on {} demo purchase order line(s).", updated)
}
}

private fun ensureAuthorities() {
val roles = listOf(
"ADMIN" to "行政",
@@ -481,6 +711,8 @@ class DemoSandboxSeeder(
uomM18 = uom
this.qty = qty
qtyM18 = qty
up = BigDecimal("12.50")
price = BigDecimal("12.50")
this.status = status
m18DataLog = dataLog
})


+ 5
- 1
src/main/java/com/ffii/fpsms/modules/deliveryOrder/service/DoPickOrderService.kt Vedi File

@@ -45,8 +45,10 @@ import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderLineRepository
import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrderRepository
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderLineRecordRepository
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderLineRecord
import org.springframework.beans.factory.ObjectProvider
import org.springframework.context.annotation.Lazy
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository
import com.ffii.fpsms.modules.common.demo.DemoSandboxSeeder
import com.ffii.fpsms.modules.deliveryOrder.web.models.TicketReleaseTableResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.TruckScheduleDashboardResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.SearchDeliveryOrderInfoRequest
@@ -64,7 +66,8 @@ open class DoPickOrderService(
private val doPickOrderLineRepository: DoPickOrderLineRepository,
@Lazy private val deliveryOrderRepository: DeliveryOrderRepository,
private val doPickOrderLineRecordRepository: DoPickOrderLineRecordRepository,
private val pickOrderLineRepository: PickOrderLineRepository
private val pickOrderLineRepository: PickOrderLineRepository,
private val demoSandboxSeeder: ObjectProvider<DemoSandboxSeeder>,
) {
open fun findReleasedDoPickOrders(): List<DoPickOrder> {
return doPickOrderRepository.findByTicketStatusIn(
@@ -847,6 +850,7 @@ open class DoPickOrderService(
* Groups DoPickOrder and DoPickOrderRecord data to provide summary statistics.
*/
open fun getTruckScheduleDashboard(targetDate: LocalDate): List<TruckScheduleDashboardResponse> {
demoSandboxSeeder.getIfAvailable()?.alignDashboardTrucksToToday()
// Source of truth: delivery_order_pick_order (+ linked pick_order / pick_order_line)
//
// NOTE: delivery_order_pick_order 沒有 truckId 欄位;dashboard 的 truckId 目前僅作為展示/鍵值用途,


+ 3
- 3
src/main/java/com/ffii/fpsms/modules/purchaseOrder/entity/projections/PurchaseOrderInfo.kt Vedi File

@@ -8,9 +8,9 @@ import java.time.LocalDateTime
interface PurchaseOrderInfo {
val id: Long
val code: String
val orderDate: LocalDateTime
val estimatedArrivalDate: LocalDateTime
val completeDate: LocalDateTime
val orderDate: LocalDateTime?
val estimatedArrivalDate: LocalDateTime?
val completeDate: LocalDateTime?
val status: String
@get:Value("#{target.supplier?.name}")
val supplier: String?


+ 2
- 2
src/main/java/com/ffii/fpsms/modules/purchaseOrder/service/PurchaseOrderService.kt Vedi File

@@ -268,7 +268,7 @@ open fun getPoSummariesByIds(ids: List<Long>): List<PurchaseOrderSummary> {
return purchaseOrderRepository.findAll()
}

open fun getDetailedPo(id: Long): Map<String, Any> {
open fun getDetailedPo(id: Long): Map<String, Any?> {
// REMINDER: po code have duplication
val po = purchaseOrderRepository.findPurchaseOrderInfoByIdAndDeletedIsFalse(id)
val pol = polRepository.findAllByPurchaseOrderIdAndDeletedIsFalse(id)
@@ -336,7 +336,7 @@ open fun getPoSummariesByIds(ids: List<Long>): List<PurchaseOrderSummary> {
.sumOf { line -> line.putAwayLines?.sumOf { it.qty?.takeIf { qty -> qty > BigDecimal.ZERO } ?: BigDecimal.ZERO } ?: BigDecimal.ZERO},
receivedQty = thisPol.stockInLines.sumOf { it.acceptedQty ?: BigDecimal.ZERO },
uom = thisPol.uomM18 ?: thisPol.uom!!,
price = thisPol.price!!,
price = thisPol.price ?: thisPol.up ?: BigDecimal.ZERO,
status = thisPol.status!!.toString(),
stockInLine = inLine,
qcItems = qcItems,


+ 1
- 1
src/main/java/com/ffii/fpsms/modules/purchaseOrder/web/PurchaseOrderController.kt Vedi File

@@ -98,7 +98,7 @@ class PurchaseOrderController(
}

@GetMapping("/detail/{id}") // purchaseOrderId
fun getDetailedPo(@PathVariable id: Long): Map<String, Any> {
fun getDetailedPo(@PathVariable id: Long): Map<String, Any?> {

/*
// tested the sample printing function by a pdf file


Caricamento…
Annulla
Salva