| @@ -0,0 +1,51 @@ | |||
| package com.ffii.fpsms.modules.master.entity | |||
| import com.ffii.core.entity.BaseEntity | |||
| import com.ffii.fpsms.modules.master.enums.ShopType | |||
| import com.ffii.fpsms.modules.master.enums.ShopTypeConverter | |||
| import jakarta.persistence.Column | |||
| import jakarta.persistence.Entity | |||
| import jakarta.persistence.PrimaryKeyJoinColumn | |||
| import jakarta.persistence.SecondaryTable | |||
| import jakarta.persistence.Table | |||
| import jakarta.validation.constraints.Size | |||
| import jakarta.validation.constraints.NotNull | |||
| import jakarta.persistence.Convert | |||
| import java.time.LocalTime | |||
| @Entity | |||
| @Table(name = "shop") | |||
| @SecondaryTable(name="Truck", pkJoinColumns = [PrimaryKeyJoinColumn(name = "shopId", referencedColumnName = "id")]) | |||
| open class ShopAndTruck : BaseEntity<Long>() { | |||
| // --- Shop fields --- | |||
| @Size(max = 300) | |||
| @NotNull | |||
| @Column(name = "name", nullable = false, length = 300) | |||
| open var name: String? = null | |||
| @Size(max = 50) | |||
| @NotNull | |||
| @Column(name = "code", nullable = false, length = 50) | |||
| open var code: String? = null | |||
| @Convert(converter = ShopTypeConverter::class) | |||
| @Column(name = "type", length = 10) | |||
| open var type: ShopType? = null | |||
| // --- Truck fields (secondary table) --- | |||
| @Column(table = "truck", name = "TruckLanceCode", length = 50) | |||
| open var truckLanceCode: String? = null | |||
| @Column(table = "truck", name = "departureTime") | |||
| open var departureTime: LocalTime? = null | |||
| @Column(table = "truck", name = "LoadingSequence") | |||
| open var loadingSequence: Long? = null | |||
| @Column(table = "truck", name = "districtReference") | |||
| open var districtReference: Long? = null | |||
| @Column(table = "truck", name = "Store_id") | |||
| open var storeId: Long? = null | |||
| } | |||
| @@ -1,8 +1,10 @@ | |||
| package com.ffii.fpsms.modules.master.entity | |||
| import com.ffii.fpsms.modules.master.entity.projections.ShopAndTruck | |||
| import com.ffii.core.support.AbstractRepository | |||
| import com.ffii.fpsms.modules.master.entity.projections.ShopCombo | |||
| import com.ffii.fpsms.modules.master.enums.ShopType | |||
| import com.ffii.fpsms.modules.pickOrder.entity.Truck | |||
| import org.springframework.data.jpa.repository.Query | |||
| import org.springframework.stereotype.Repository | |||
| @@ -27,4 +29,16 @@ interface ShopRepository : AbstractRepository<Shop, Long> { | |||
| fun findShopComboByTypeAndDeletedIsFalse(type: ShopType): List<ShopCombo> | |||
| fun findByCode(code: String): Shop? | |||
| } | |||
| @Query( | |||
| nativeQuery = true, | |||
| value = """ | |||
| SELECT s.id, s.code, s.name, s.contactNo, s.contactEmail, s.contactName, s.addr1, s.addr2, s.addr3, s.type, t.TruckLanceCode, t.LoadingSequence, t.districtReference,t.Store_id | |||
| FROM shop s LEFT JOIN truck t ON s.id = t.shopId | |||
| WHERE s.type = 'shop' | |||
| AND s.deleted = false; | |||
| """ | |||
| ) | |||
| fun findAllByTypeAndDeletedIsFalse(): List<ShopAndTruck>? | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| package com.ffii.fpsms.modules.master.entity.projections | |||
| import java.time.LocalTime | |||
| interface ShopAndTruck { | |||
| val id: Long | |||
| val name: String? | |||
| val code: String? | |||
| val contactNo: String? | |||
| val contactEmail: String? | |||
| val contactName: String? | |||
| val addr1: String? | |||
| val addr2: String? | |||
| val addr3: String? | |||
| val type: String? | |||
| val truckLanceCode: String? | |||
| val departureTime: LocalTime? | |||
| val LoadingSequence: Long? | |||
| val districtReference: Long? | |||
| val Store_id: Long? | |||
| } | |||
| @@ -2,6 +2,7 @@ package com.ffii.fpsms.modules.master.service | |||
| import com.ffii.fpsms.modules.master.entity.Shop | |||
| import com.ffii.fpsms.modules.master.entity.ShopRepository | |||
| import com.ffii.fpsms.modules.master.entity.projections.ShopAndTruck | |||
| import com.ffii.fpsms.modules.master.entity.projections.ShopCombo | |||
| import com.ffii.fpsms.modules.master.enums.ShopType | |||
| import com.ffii.fpsms.modules.master.web.models.SaveShopRequest | |||
| @@ -47,6 +48,9 @@ open class ShopService( | |||
| return shopRepository.findShopComboByTypeAndDeletedIsFalse(ShopType.SHOP) | |||
| } | |||
| open fun findAllByTypeAndDeletedIsFalse(): List<ShopAndTruck>?{ | |||
| return shopRepository.findAllByTypeAndDeletedIsFalse() | |||
| } | |||
| open fun saveShop(request: SaveShopRequest): SaveShopResponse { | |||
| val shop = if (request.m18Id != null) { | |||
| when (request.type){ | |||
| @@ -1,7 +1,13 @@ | |||
| package com.ffii.fpsms.modules.master.web | |||
| import com.ffii.fpsms.modules.master.entity.ShopRepository | |||
| import com.ffii.fpsms.modules.master.entity.Shop | |||
| import com.ffii.fpsms.modules.master.entity.projections.ShopAndTruck | |||
| import com.ffii.fpsms.modules.master.entity.projections.ShopCombo | |||
| import com.ffii.fpsms.modules.master.enums.ShopType | |||
| import com.ffii.fpsms.modules.master.service.ShopService | |||
| import com.ffii.fpsms.modules.pickOrder.entity.Truck | |||
| import org.springframework.web.bind.annotation.GetMapping | |||
| import org.springframework.web.bind.annotation.RequestMapping | |||
| import org.springframework.web.bind.annotation.RestController | |||
| @@ -20,4 +26,11 @@ class ShopController ( | |||
| fun getSupplierCombo(): List<ShopCombo> { | |||
| return shopService.findSupplierCombo(); | |||
| } | |||
| @GetMapping("/combo/allShop") | |||
| fun test3(): List<ShopAndTruck>? { | |||
| return shopService.findAllByTypeAndDeletedIsFalse(); | |||
| } | |||
| } | |||
| @@ -18,4 +18,4 @@ data class SaveShopRequest ( | |||
| val type: String?, | |||
| val m18Id: Long?, | |||
| val m18LastModifyDate: LocalDateTime?, | |||
| ) | |||
| ) | |||
| @@ -34,4 +34,8 @@ open class Truck : BaseEntity<Long>() { | |||
| @Column(name = "Store_id") | |||
| open var storeId: Int? = null | |||
| @Column(name = "districtReference") | |||
| open var districtReference: Int? = null | |||
| } | |||
| @@ -4,6 +4,9 @@ import com.ffii.core.support.AbstractRepository | |||
| import org.springframework.data.jpa.repository.Query | |||
| import org.springframework.data.repository.query.Param | |||
| import org.springframework.stereotype.Repository | |||
| import java.time.LocalTime | |||
| import java.util.Optional | |||
| @Repository | |||
| interface TruckRepository : AbstractRepository<Truck, Long> { | |||
| @@ -29,4 +32,9 @@ interface TruckRepository : AbstractRepository<Truck, Long> { | |||
| fun findByTruckLanceCode(truckLanceCode: String): Truck? | |||
| fun findByShopNameAndStoreIdAndTruckLanceCode(shopName: String, storeId: Int, truckLanceCode: String): Truck? | |||
| fun findByShopCodeAndStoreId(shopCode: String, storeId: Int): Truck? | |||
| fun findAllByShopId(shopId :Long):List<Truck> | |||
| //fun findByTruckLanceCode(truckLanceCode: String):List<Truck> | |||
| //fun deleteByTruckLanceCodeAndDepartureTimeAndLoadingSequenceAndDistrictReferenceAndStoreId(truckLanceCode: String, departureTime: LocalTime, loadingSequence: Long, districtReference: Long, storeId: Long): String | |||
| } | |||
| @@ -3,33 +3,19 @@ package com.ffii.fpsms.modules.pickOrder.service | |||
| import com.ffii.core.support.AbstractBaseEntityService | |||
| import com.ffii.core.support.JdbcDao | |||
| import com.ffii.core.utils.ExcelUtils | |||
| import com.ffii.core.utils.JwtTokenUtil | |||
| import com.ffii.fpsms.modules.master.entity.ItemsRepository | |||
| 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 | |||
| import com.ffii.fpsms.modules.stock.entity.StockInLineRepository | |||
| import com.ffii.fpsms.modules.stock.entity.StockInRepository | |||
| import com.ffii.fpsms.modules.stock.service.InventoryLotService | |||
| import com.ffii.fpsms.modules.stock.service.StockInService | |||
| import org.apache.poi.ss.usermodel.Sheet | |||
| import org.apache.poi.ss.usermodel.Workbook | |||
| import org.slf4j.Logger | |||
| import org.slf4j.LoggerFactory | |||
| import org.springframework.stereotype.Service | |||
| import java.math.BigDecimal | |||
| import kotlin.jvm.optionals.getOrNull | |||
| import com.ffii.fpsms.modules.pickOrder.entity.Truck | |||
| import com.ffii.fpsms.modules.pickOrder.entity.TruckRepository | |||
| import com.ffii.fpsms.modules.pickOrder.web.models.SaveTruckRequest | |||
| import java.time.LocalTime | |||
| import java.time.format.DateTimeFormatter | |||
| import com.ffii.fpsms.modules.master.entity.ShopRepository | |||
| import com.ffii.fpsms.modules.pickOrder.web.models.SaveTruckLane | |||
| import jakarta.transaction.Transactional | |||
| @Service | |||
| open class TruckService( | |||
| private val jdbcDao: JdbcDao, | |||
| @@ -37,8 +23,8 @@ open class TruckService( | |||
| private val shopRepository: ShopRepository, | |||
| ) : AbstractBaseEntityService<Truck, Long, TruckRepository>(jdbcDao, truckRepository) { | |||
| open fun saveTruck(request: SaveTruckRequest): Truck { | |||
| val truck = request.id?.let { | |||
| truckRepository.findById(it).orElse(null) | |||
| val truck = request.id?.let { | |||
| truckRepository.findById(it).orElse(null) | |||
| } ?: Truck() | |||
| val shop = shopRepository.findById(request.shopId).orElse(null) | |||
| if (shop == null) { | |||
| @@ -91,22 +77,24 @@ open class TruckService( | |||
| null | |||
| } | |||
| } | |||
| private fun normalizeShopCode(shopCode: String): String { | |||
| val firstDigitIndex = shopCode.indexOfFirst { it.isDigit() } | |||
| if (firstDigitIndex == -1) { | |||
| return shopCode | |||
| return shopCode | |||
| } | |||
| val letterPart = shopCode.substring(0, firstDigitIndex) | |||
| val numberPart = shopCode.substring(firstDigitIndex) | |||
| val normalizedNumber = if (numberPart.startsWith("0") && numberPart.length > 1) { | |||
| numberPart.substring(1) | |||
| numberPart.substring(1) | |||
| } else { | |||
| numberPart | |||
| numberPart | |||
| } | |||
| return letterPart + normalizedNumber | |||
| } | |||
| open fun importExcel(workbook: Workbook?): String { | |||
| logger.info("--------- Start - Import Warehouse Excel -------"); | |||
| @@ -160,14 +148,14 @@ open class TruckService( | |||
| //println("shop: ${shop}") | |||
| val existingTruck = truckRepository.findByShopCodeAndStoreId(shopCode, storeIdInt) | |||
| if (existingTruck != null) { | |||
| val truckRequest = SaveTruckRequest( | |||
| id = existingTruck.id, | |||
| store_id = storeIdInt, | |||
| store_id = storeIdInt, | |||
| truckLanceCode = truckLanceCode ?: existingTruck.truckLanceCode ?: "", | |||
| departureTime = departureTime, | |||
| shopId = shop?.id!!, | |||
| shopName = shopName?: "", | |||
| shopName = shopName ?: "", | |||
| shopCode = normalizedShopCode, | |||
| loadingSequence = loadingSequence | |||
| ) | |||
| @@ -176,11 +164,11 @@ open class TruckService( | |||
| // 创建新记录 | |||
| val truckRequest = SaveTruckRequest( | |||
| id = null, | |||
| store_id = storeIdInt, | |||
| store_id = storeIdInt, | |||
| truckLanceCode = truckLanceCode ?: "", | |||
| departureTime = departureTime, | |||
| shopId = shop?.id!!, | |||
| shopName = shopName?: "", | |||
| shopName = shopName ?: "", | |||
| shopCode = normalizedShopCode, | |||
| loadingSequence = loadingSequence | |||
| ) | |||
| @@ -195,4 +183,55 @@ open class TruckService( | |||
| return "Import Excel success"; | |||
| } | |||
| open fun findAllByShopId(shopId: Long): List<Truck> { | |||
| return truckRepository.findAllByShopId(shopId) | |||
| } | |||
| @Transactional | |||
| open fun updateTruckLaneByTruckLanceCode(request: SaveTruckLane): List<Truck> { | |||
| val updateTruckLance = truckRepository.findById(request.id).orElseThrow() | |||
| ?: throw IllegalArgumentException("Truck not found with truckLanceCode: $request.truckLanceCode") | |||
| //println(updateTruckLance,"before") | |||
| updateTruckLance.truckLanceCode = request.truckLanceCode | |||
| updateTruckLance.loadingSequence = request.loadingSequence.toInt() | |||
| updateTruckLance.districtReference = request.districtReference.toInt() | |||
| updateTruckLance.departureTime = request.departureTime | |||
| updateTruckLance.storeId = request.storeId.toInt() | |||
| val savedTruck = truckRepository.save(updateTruckLance) | |||
| //print(updateTruckLance,"after") | |||
| return listOf(savedTruck) | |||
| } | |||
| @Transactional | |||
| open fun deleteById(id: Long): String { | |||
| truckRepository.deleteById(id) | |||
| return "Truck deleted successfully with id: $id" | |||
| } | |||
| @Transactional | |||
| open fun createTruck(request: SaveTruckRequest): Truck { | |||
| // Always create a new truck, ignore id if provided | |||
| val truck = Truck() | |||
| val shop = shopRepository.findById(request.shopId).orElse(null) | |||
| if (shop == null) { | |||
| throw IllegalArgumentException("Shop not found with id: ${request.shopId}") | |||
| } | |||
| truck.apply { | |||
| this.storeId = request.store_id | |||
| this.truckLanceCode = request.truckLanceCode | |||
| this.departureTime = request.departureTime | |||
| this.shop = shop | |||
| this.shopName = request.shopName | |||
| this.shopCode = request.shopCode | |||
| this.loadingSequence = request.loadingSequence | |||
| this.districtReference = request.districtReference | |||
| } | |||
| return truckRepository.save(truck) | |||
| } | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| package com.ffii.fpsms.modules.pickOrder.web.models | |||
| import java.time.LocalTime | |||
| data class SaveTruckRequest( | |||
| val id: Long? = null, | |||
| val store_id: Int, | |||
| val truckLanceCode: String, | |||
| val departureTime: LocalTime, | |||
| val shopId: Long, | |||
| val shopName: String, | |||
| val shopCode: String, | |||
| val loadingSequence: Int, | |||
| val districtReference: Int? = null, | |||
| ) | |||
| data class SaveTruckLane( | |||
| val id: Long, | |||
| val truckLanceCode: String, | |||
| val departureTime: LocalTime, | |||
| val loadingSequence: Long, | |||
| val districtReference: Long, | |||
| val storeId: Int | |||
| ) | |||
| data class deleteTruckLane( | |||
| val id: Long | |||
| ) | |||
| @@ -1,6 +1,7 @@ | |||
| package com.ffii.fpsms.modules.pickOrder.web | |||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||
| import com.ffii.fpsms.modules.pickOrder.entity.Truck | |||
| import org.springframework.web.bind.ServletRequestBindingException | |||
| import jakarta.servlet.http.HttpServletRequest | |||
| import org.apache.poi.ss.usermodel.Workbook | |||
| @@ -12,6 +13,9 @@ import org.springframework.web.multipart.MultipartHttpServletRequest | |||
| import com.ffii.fpsms.modules.pickOrder.web.models.SaveTruckRequest | |||
| import com.ffii.fpsms.modules.pickOrder.service.TruckService | |||
| import com.ffii.fpsms.modules.pickOrder.entity.TruckRepository | |||
| import com.ffii.fpsms.modules.pickOrder.web.models.SaveTruckLane | |||
| import com.ffii.fpsms.modules.pickOrder.web.models.deleteTruckLane | |||
| import jakarta.validation.Valid | |||
| @RestController | |||
| @RequestMapping("/truck") | |||
| @@ -45,6 +49,33 @@ class TruckController( | |||
| ) | |||
| } | |||
| } | |||
| @PostMapping("/create") | |||
| fun createTruck(@Valid @RequestBody request: SaveTruckRequest): MessageResponse { | |||
| try { | |||
| val truck = truckService.createTruck(request) | |||
| return MessageResponse( | |||
| id = truck.id, | |||
| name = truck.shopName, | |||
| code = truck.truckLanceCode, | |||
| type = "truck", | |||
| message = "Truck created successfully", | |||
| errorPosition = null, | |||
| entity = truck | |||
| ) | |||
| } catch (e: Exception) { | |||
| return MessageResponse( | |||
| id = null, | |||
| name = null, | |||
| code = null, | |||
| type = "truck", | |||
| message = "Error: ${e.message}", | |||
| errorPosition = null, | |||
| entity = null | |||
| ) | |||
| } | |||
| } | |||
| @PostMapping("/importExcel") | |||
| @Throws(ServletRequestBindingException::class) | |||
| fun importExcel(request: HttpServletRequest): ResponseEntity<*> { | |||
| @@ -82,4 +113,63 @@ class TruckController( | |||
| ) | |||
| } | |||
| } | |||
| @GetMapping("/findTruckLane/{shopId}") | |||
| fun findAllByShopId(@PathVariable shopId: Long): List<Truck> { | |||
| return truckService.findAllByShopId(shopId); | |||
| } | |||
| @PostMapping("/updateTruckLane") | |||
| fun updateTruckLane(@Valid @RequestBody request: SaveTruckLane): MessageResponse { | |||
| try { | |||
| val trucks = truckService.updateTruckLaneByTruckLanceCode( | |||
| request | |||
| ) | |||
| val truck = trucks.firstOrNull() | |||
| return MessageResponse( | |||
| id = truck?.id, | |||
| name = truck?.shopName, | |||
| code = truck?.truckLanceCode, | |||
| type = "truck", | |||
| message = if (truck != null) "Truck lane updated successfully" else "Truck lane not found", | |||
| errorPosition = null, | |||
| entity = truck | |||
| ) | |||
| } catch (e: Exception) { | |||
| return MessageResponse( | |||
| id = null, | |||
| name = null, | |||
| code = null, | |||
| type = "truck", | |||
| message = "Error: ${e.message}", | |||
| errorPosition = null, | |||
| entity = null | |||
| ) | |||
| } | |||
| } | |||
| @PostMapping("/deleteTruckLane") | |||
| fun deleteTruckLane(@Valid @RequestBody request: deleteTruckLane): MessageResponse { | |||
| try { | |||
| val result = truckService.deleteById(request.id) | |||
| return MessageResponse( | |||
| id = request.id, | |||
| name = null, | |||
| code = null, | |||
| type = "truck", | |||
| message = result, | |||
| errorPosition = null, | |||
| entity = null | |||
| ) | |||
| } catch (e: Exception) { | |||
| return MessageResponse( | |||
| id = null, | |||
| name = null, | |||
| code = null, | |||
| type = "truck", | |||
| message = "Error: ${e.message}", | |||
| errorPosition = null, | |||
| entity = null | |||
| ) | |||
| } | |||
| } | |||
| } | |||
| @@ -9,4 +9,16 @@ data class SaveTruckRequest( | |||
| val shopName: String, | |||
| val shopCode: String, | |||
| val loadingSequence: Int, | |||
| val districtReference: Int? = null, | |||
| ) | |||
| data class SaveTruckLane( | |||
| val id: Long, | |||
| val truckLanceCode: String, | |||
| val departureTime: LocalTime, | |||
| val loadingSequence: Long, | |||
| val districtReference: Long, | |||
| val storeId: Int | |||
| ) | |||
| data class deleteTruckLane( | |||
| val id: Long | |||
| ) | |||