CANCERYS\kw093 пре 3 недеља
родитељ
комит
9545bc4fbc
10 измењених фајлова са 362 додато и 4 уклоњено
  1. +18
    -2
      src/main/java/com/ffii/fpsms/modules/master/entity/Warehouse.kt
  2. +231
    -1
      src/main/java/com/ffii/fpsms/modules/master/service/WarehouseService.kt
  3. +14
    -0
      src/main/java/com/ffii/fpsms/modules/master/web/WarehouseController.kt
  4. +21
    -0
      src/main/java/com/ffii/fpsms/modules/master/web/models/SaveWarehouseRequest.kt
  5. +1
    -1
      src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt
  6. +12
    -0
      src/main/resources/db/changelog/changes/20251122_01_enson/01_altertable_enson.sql
  7. +10
    -0
      src/main/resources/db/changelog/changes/20251122_01_enson/02_altertable_enson.sql
  8. +8
    -0
      src/main/resources/db/changelog/changes/20251122_01_enson/03_altertable_enson.sql
  9. +5
    -0
      src/main/resources/db/changelog/changes/20251122_01_enson/04_altertable_enson.sql
  10. +42
    -0
      src/main/resources/db/changelog/changes/20251122_01_enson/05_altertable_enson.sql

+ 18
- 2
src/main/java/com/ffii/fpsms/modules/master/entity/Warehouse.kt Прегледај датотеку

@@ -15,8 +15,8 @@ open class Warehouse : BaseEntity<Long>() {
@Column(name = "code", nullable = false, length = 30)
open var code: String? = null
@NotNull
@Column(name = "order", nullable = false, length = 30)
open var order: String? = null
@Column(name = "`order`", nullable = false,)
open var order: Int? = null
@NotNull
@Column(name = "name", nullable = false, length = 30)
open var name: String? = null
@@ -28,4 +28,20 @@ open class Warehouse : BaseEntity<Long>() {
@NotNull
@Column(name = "capacity", nullable = false, precision = 14, scale = 2)
open var capacity: BigDecimal? = null


@Column(name = "store_id", nullable = false, length = 30)
open var store_id: String? = null
@Column(name = "storeLocation", nullable = true, length = 30)
open var storeLocation: String? = null
@Column(name = "stockTakeTable", nullable = true, length = 30)
open var stockTakeTable: String? = null
@Column(name = "company", nullable = true, length = 30)
open var company: String? = null
@Column(name = "warehouse", nullable = true, length = 30)
open var warehouse: String? = null
@Column(name = "area", nullable = true, length = 30)
open var area: String? = null
@Column(name = "slot", nullable = true, length = 30)
open var slot: String? = null
}

+ 231
- 1
src/main/java/com/ffii/fpsms/modules/master/service/WarehouseService.kt Прегледај датотеку

@@ -9,6 +9,7 @@ import com.ffii.fpsms.modules.master.entity.Warehouse
import com.ffii.fpsms.modules.master.entity.WarehouseRepository
import com.ffii.fpsms.modules.master.entity.projections.WarehouseCombo
import com.ffii.fpsms.modules.master.web.models.SaveWarehouseRequest
import com.ffii.fpsms.modules.master.web.models.NewWarehouseRequest
import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderLineRepository
import com.ffii.fpsms.modules.stock.entity.InventoryLotRepository
import com.ffii.fpsms.modules.stock.entity.StockInLine
@@ -23,7 +24,7 @@ import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.math.BigDecimal
import kotlin.jvm.optionals.getOrNull
import com.ffii.fpsms.modules.master.web.models.ExcelWarehouseData
@Service
open class WarehouseService(
private val jdbcDao: JdbcDao,
@@ -109,4 +110,233 @@ open class WarehouseService(
logger.info("--------- End - Import Warehouse Excel -------")
return "Import Excel success";
}
open fun importNewExcel(workbook: Workbook?): String {
logger.info("--------- Start - Import Warehouse Excel -------");
if (workbook == null) {
logger.error("No Excel Import");
return "Import Excel failure";
}
val sheet: Sheet = workbook.getSheetAt(0);
// Columns
val COLUMN_WAREHOSE_INDEX = 1;
val COLUMN_ZONE_INDEX = 2;
val COLUMN_SLOT_INDEX = 3;
val COLUMN_FLOOR_INDEX = 4;
val COLUMN_PICK_ROUTING_INDEX = 5;
val COLUMN_STORE_LOCATION_INDEX = 6;
val COLUMN_STOCK_TAKE_TABLE_INDEX = 7;
val COLUMN_COMPANY_INDEX = 8;
val START_ROW_INDEX = 5;
// 第一步:收集所有 Excel 数据(包含行索引,用于调试)
data class ExcelWarehouseDataWithRow(
val rowIndex: Int,
val warehouse: String,
val area: String,
val slot: String
)
val excelDataList = mutableListOf<ExcelWarehouseDataWithRow>()
var skippedRows = 0
for (i in START_ROW_INDEX..<sheet.lastRowNum) {
val row = sheet.getRow(i)
if (row == null) {
skippedRows++
continue
}
try {
val warehouse = ExcelUtils.getStringValue(row.getCell(COLUMN_WAREHOSE_INDEX))?.trim()
val area = ExcelUtils.getStringValue(row.getCell(COLUMN_ZONE_INDEX))?.trim()
val slot = ExcelUtils.getStringValue(row.getCell(COLUMN_SLOT_INDEX))?.trim()
if (warehouse.isNullOrBlank() || area.isNullOrBlank() || slot.isNullOrBlank()) {
skippedRows++
continue
}
excelDataList.add(ExcelWarehouseDataWithRow(i, warehouse, area, slot))
} catch (e: Exception) {
logger.error("Read Error (Row ${i + 1}): ${e.message}")
skippedRows++
}
}
logger.info("Total rows in Excel: ${sheet.lastRowNum - START_ROW_INDEX + 1}, Valid rows collected: ${excelDataList.size}, Skipped: $skippedRows")
// 第二步:计算 order 映射(使用 ExcelWarehouseData)
val excelDataForOrder = excelDataList.map {
ExcelWarehouseData(it.warehouse, it.area, it.slot)
}
val orderMap = calculateOrderMap(excelDataForOrder)
logger.info("Order map size: ${orderMap.size}")
// 第三步:在循环中使用 orderMap 匹配
var updateCount = 0
var createCount = 0
var skippedInSecondLoop = 0
val processedKeys = mutableSetOf<String>()
for (i in START_ROW_INDEX..<sheet.lastRowNum) {
val row = sheet.getRow(i)
if (row == null) continue
try {
val warehouse = ExcelUtils.getStringValue(row.getCell(COLUMN_WAREHOSE_INDEX))?.trim()
val area = ExcelUtils.getStringValue(row.getCell(COLUMN_ZONE_INDEX))?.trim()
val slot = ExcelUtils.getStringValue(row.getCell(COLUMN_SLOT_INDEX))?.trim()
val store_id = ExcelUtils.getStringValue(row.getCell(COLUMN_FLOOR_INDEX))?.trim()
val storeLocation = ExcelUtils.getStringValue(row.getCell(COLUMN_STORE_LOCATION_INDEX))?.trim()
val stockTakeTable = ExcelUtils.getStringValue(row.getCell(COLUMN_STOCK_TAKE_TABLE_INDEX))?.trim()
val company = ExcelUtils.getStringValue(row.getCell(COLUMN_COMPANY_INDEX))?.trim()
if (warehouse.isNullOrBlank() || area.isNullOrBlank() || slot.isNullOrBlank()) {
skippedInSecondLoop++
continue
}
// 使用唯一标识从 orderMap 获取 order
val uniqueKey = "$warehouse-$area-$slot"
val order = orderMap[uniqueKey]
if (order == null) {
logger.warn("Order not found for key: $uniqueKey at row ${i + 1}")
skippedInSecondLoop++
continue
}
val capacity = BigDecimal(10000)
val code = "$store_id-$warehouse-$area-$slot"
val name = "$store_id-$storeLocation"
val description = "$store_id-$storeLocation"
// 检查是否已经处理过这个 uniqueKey(避免重复处理)
if (processedKeys.contains(uniqueKey)) {
logger.warn("Duplicate key found: $uniqueKey at row ${i + 1}, skipping")
skippedInSecondLoop++
continue
}
processedKeys.add(uniqueKey)
// 查找现有仓库
val existingWarehouse = warehouseRepository.findAll()
.firstOrNull {
it.code == code && it.deleted == false
} ?: warehouseRepository.findAll()
.firstOrNull {
it.warehouse == warehouse &&
it.area == area &&
it.slot == slot &&
it.deleted == false
}
if (existingWarehouse != null) {
// 更新
existingWarehouse.apply {
this.code = code
this.name = name
this.description = description
this.warehouse = warehouse
this.area = area
this.store_id = store_id
this.slot = slot
this.order = order
this.storeLocation = storeLocation
this.stockTakeTable = stockTakeTable
this.company = company
}
warehouseRepository.save(existingWarehouse)
updateCount++
} else {
// 创建
val newWarehouse = Warehouse().apply {
this.code = code
this.name = name
this.description = description
this.capacity = capacity
this.warehouse = warehouse
this.area = area
this.store_id = store_id
this.slot = slot
this.order = order
this.storeLocation = storeLocation
this.stockTakeTable = stockTakeTable
this.company = company
}
warehouseRepository.save(newWarehouse)
createCount++
}
} catch (e: Exception) {
logger.error("Import Error (Row ${i + 1}): ${e.message}")
skippedInSecondLoop++
}
}
logger.info("--------- End - Import Warehouse Excel - Created: $createCount, Updated: $updateCount, Skipped in second loop: $skippedInSecondLoop -------")
return "Import Excel success - Created: $createCount, Updated: $updateCount, Skipped: $skippedInSecondLoop";
}

// 计算 order 映射:接收 Excel 数据列表,返回 Map<唯一标识, order>
private fun calculateOrderMap(excelDataList: List<ExcelWarehouseData>): Map<String, Int> {
data class WarehouseWithSort(
val data: ExcelWarehouseData,
val sortValue: Long,
val uniqueKey: String
)

val sortedWarehouses = excelDataList.map { data ->
val slot = data.slot.toIntOrNull() ?: 0
val sortValue = calculateSortValue(data.warehouse, data.area, slot)
val uniqueKey = "${data.warehouse}-${data.area}-${data.slot}"
WarehouseWithSort(data, sortValue, uniqueKey)
}.sortedBy { it.sortValue }

// 分配连续的 order(1, 2, 3...),类似 ROW_NUMBER()
return sortedWarehouses.mapIndexed { index, warehouseWithSort ->
warehouseWithSort.uniqueKey to (index + 1) // 唯一标识 -> order
}.toMap()
}
// 计算单个仓库的排序值(与 MySQL 逻辑一致)
private fun calculateSortValue(warehouseStr: String, areaStr: String, slot: Int): Long {
// 提取楼层号
val floorNumber = if (warehouseStr.length >= 2) {
warehouseStr.substring(1, 2).toIntOrNull() ?: 99
} else 99
// 提取字母部分
val letterPart = if (areaStr.startsWith("#") && areaStr.length >= 2) {
areaStr.substring(1, 2)
} else null
// 计算楼层排序值
val floorOrder = when (floorNumber) {
2 -> 1
3 -> 2
4 -> 3
else -> 99
}
// 计算字母排序值(与 MySQL 逻辑一致)
val letterOrder = when {
letterPart == null -> 9999
letterPart in listOf("C", "B", "A", "E", "F", "G", "H", "I", "N", "M", "L", "P", "Q", "R", "S", "Y", "O", "K", "D") -> {
val orderMap = mapOf(
"C" to 1, "B" to 2, "A" to 3, "E" to 4, "F" to 5, "G" to 6, "H" to 7, "I" to 8,
"N" to 9, "M" to 10, "L" to 11, "P" to 12, "Q" to 13, "R" to 14, "S" to 15,
"Y" to 16, "O" to 17, "K" to 18, "D" to 19
)
orderMap[letterPart] ?: 9999
}
else -> 1000 + letterPart[0].code
}
// 计算总排序值:楼层 * 10000 + 字母 * 100 + slot
return floorOrder * 10000L + letterOrder * 100L + slot
}
}

+ 14
- 0
src/main/java/com/ffii/fpsms/modules/master/web/WarehouseController.kt Прегледај датотеку

@@ -43,4 +43,18 @@ class WarehouseController(

return ResponseEntity.ok(warehouseService.importExcel(workbook))
}
@PostMapping("/importNew")
@Throws(ServletRequestBindingException::class)
fun importNewExcel(request: HttpServletRequest): ResponseEntity<*> {
var workbook: Workbook? = null;

try {
val multipartFile = (request as MultipartHttpServletRequest).getFile("multipartFileList")
workbook = XSSFWorkbook(multipartFile?.inputStream)
} catch (e: Exception) {
println(e)
}

return ResponseEntity.ok(warehouseService.importNewExcel(workbook))
}
}

+ 21
- 0
src/main/java/com/ffii/fpsms/modules/master/web/models/SaveWarehouseRequest.kt Прегледај датотеку

@@ -9,3 +9,24 @@ data class SaveWarehouseRequest(
val description: String,
val capacity: BigDecimal,
)
data class NewWarehouseRequest(

val id: Long? = null,
val code: String,
val name: String,
val description: String,
val capacity: BigDecimal,
val warehouse: String,
val area: String,
val slot: String,
val store_id: String,
val order: Int,
val storeLocation: String,
val stockTakeTable: String,
val company: String,
)
data class ExcelWarehouseData(
val warehouse: String,
val area: String,
val slot: String
)

+ 1
- 1
src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt Прегледај датотеку

@@ -5206,7 +5206,7 @@ open fun getLotDetailsByDoPickOrderRecordId(doPickOrderRecordId: Long): Map<Stri
stockOutLineQty = stockOutLine?.qty?.let { numToBigDecimal(it as? Number) },
router = RouterInfoResponse(
id = null,
index = w?.order,
index = w?.order.toString(),
route = w?.code,
area = w?.code
)


+ 12
- 0
src/main/resources/db/changelog/changes/20251122_01_enson/01_altertable_enson.sql Прегледај датотеку

@@ -0,0 +1,12 @@
-- liquibase formatted sql
-- changeset enson:altertable_enson

ALTER TABLE `fpsmsdb`.`warehouse`
ADD COLUMN `storeLocation` VARCHAR(255) After `store_id`,
ADD COLUMN `stockTakeTable` INT After `storeLocation`,
ADD COLUMN `Company` INT After `stockTakeTable`,
ADD COLUMN `warehouse` INT After `description`,
Add Column `area` INT After `warehouse`,
Add Column `slot` INT After `area`,
Add Column `storeTakeTable` INT After `slot`;


+ 10
- 0
src/main/resources/db/changelog/changes/20251122_01_enson/02_altertable_enson.sql Прегледај датотеку

@@ -0,0 +1,10 @@
-- liquibase formatted sql
-- changeset enson:altertable_enson

ALTER TABLE `fpsmsdb`.`warehouse`
Drop Column `storeTakeTable`,
drop Column `Company`,
add column `storeTakeTable` VARCHAR(255) After `storeLocation`,
Add Column `company` VARCHAR(255) After `storeTakeTable`;



+ 8
- 0
src/main/resources/db/changelog/changes/20251122_01_enson/03_altertable_enson.sql Прегледај датотеку

@@ -0,0 +1,8 @@
-- liquibase formatted sql
-- changeset enson:altertable_enson

ALTER TABLE `fpsmsdb`.`warehouse`
MODIFY COLUMN `warehouse` VARCHAR(30),
MODIFY COLUMN `area` VARCHAR(30),
MODIFY COLUMN `slot` VARCHAR(30);


+ 5
- 0
src/main/resources/db/changelog/changes/20251122_01_enson/04_altertable_enson.sql Прегледај датотеку

@@ -0,0 +1,5 @@
-- liquibase formatted sql
-- changeset enson:altertable_enson

ALTER TABLE `fpsmsdb`.`warehouse`
MODIFY COLUMN `stockTakeTable` VARCHAR(255);

+ 42
- 0
src/main/resources/db/changelog/changes/20251122_01_enson/05_altertable_enson.sql Прегледај датотеку

@@ -0,0 +1,42 @@
-- liquibase formatted sql
-- changeset enson:altertable_enson

SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS `fpsmsdb`.`warehouse`;


CREATE TABLE `warehouse`
(
`id` INT NOT NULL AUTO_INCREMENT,
`created` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`createdBy` VARCHAR(30) NULL DEFAULT NULL,
`version` INT NOT NULL DEFAULT '0',
`modified` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modifiedBy` VARCHAR(30) NULL DEFAULT NULL,
`deleted` TINYINT(1) NOT NULL DEFAULT '0',
`code` VARCHAR(30) NOT NULL,
`name` VARCHAR(30) NOT NULL,
`description` VARCHAR(30) NOT NULL,
`capacity` DECIMAL(14, 2) NOT NULL,
`warehouse` VARCHAR(30) NULL DEFAULT NULL,
`area` VARCHAR(30) NULL DEFAULT NULL,
`slot` VARCHAR(30) NULL DEFAULT NULL,
`order` INT NULL DEFAULT NULL,
`store_id` VARCHAR(50) NULL DEFAULT NULL,
`storeLocation` VARCHAR(255) NULL DEFAULT NULL,
`stockTakeTable` VARCHAR(255) NULL DEFAULT NULL,
`company` VARCHAR(255) NULL DEFAULT NULL,
CONSTRAINT pk_warehouse PRIMARY KEY (id)
);

SET FOREIGN_KEY_CHECKS = 1;


ALTER TABLE `fpsmsdb`.`items`
add column `storeLocation` VARCHAR(255) After `store_id`,
add column `warehouse` VARCHAR(255) After `storeLocation`,
add column `area` VARCHAR(255) After `warehouse`,
add column `slot` VARCHAR(255) After `area`,
add column `LocationCode` VARCHAR(255) After `MTMSPickRoutingID`,
add column `Uom` VARCHAR(255) After `uomId`;

Loading…
Откажи
Сачувај