| @@ -0,0 +1,94 @@ | |||||
| package com.ffii.fpsms.modules.deliveryOrder.entity | |||||
| import jakarta.persistence.* | |||||
| import java.time.LocalDateTime | |||||
| import java.time.LocalTime | |||||
| import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus | |||||
| import org.hibernate.annotations.CreationTimestamp | |||||
| import org.hibernate.annotations.UpdateTimestamp | |||||
| @Entity | |||||
| @Table(name = "do_pick_order") | |||||
| class DoPickOrder { | |||||
| @Id | |||||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | |||||
| var id: Long? = null | |||||
| @Column(name = "store_id", length = 10) | |||||
| var storeId: String? = null | |||||
| @Column(name = "ticket_no", length = 50) | |||||
| var ticketNo: String? = null | |||||
| @Enumerated(EnumType.STRING) | |||||
| @Column(name = "ticket_status") | |||||
| var ticketStatus: DoPickOrderStatus? = null | |||||
| @Column(name = "truck_id") | |||||
| var truckId: Long? = null | |||||
| @Column(name = "truck_departure_time") | |||||
| var truckDepartureTime: LocalTime? = null | |||||
| @Column(name = "item_id") | |||||
| var itemId: Long? = null | |||||
| @Column(name = "shop_id") | |||||
| var shopId: Long? = null | |||||
| @Column(name = "shop_po_supplier_id") | |||||
| var shopPoSupplierId: Long? = null | |||||
| @Column(name = "handled_by") | |||||
| var handledBy: Long? = null | |||||
| @CreationTimestamp | |||||
| @Column(name = "created") | |||||
| var created: LocalDateTime? = null | |||||
| @Column(name = "createdBy", length = 30) | |||||
| var createdBy: String? = null | |||||
| @Version | |||||
| var version: Int = 0 | |||||
| @UpdateTimestamp | |||||
| @Column(name = "modified") | |||||
| var modified: LocalDateTime? = null | |||||
| @Column(name = "modifiedBy", length = 30) | |||||
| var modifiedBy: String? = null | |||||
| @Column(name = "deleted") | |||||
| var deleted: Boolean = false | |||||
| // Default constructor for Hibernate | |||||
| constructor() | |||||
| // Constructor for creating new instances | |||||
| constructor( | |||||
| storeId: String, | |||||
| ticketNo: String, | |||||
| ticketStatus: DoPickOrderStatus, | |||||
| truckId: Long? = null, | |||||
| truckDepartureTime: LocalTime? = null, | |||||
| itemId: Long? = null, | |||||
| shopId: Long? = null, | |||||
| shopPoSupplierId: Long? = null, | |||||
| handledBy: Long? = null, | |||||
| createdBy: String? = null, | |||||
| modifiedBy: String? = null | |||||
| ) { | |||||
| this.storeId = storeId | |||||
| this.ticketNo = ticketNo | |||||
| this.ticketStatus = ticketStatus | |||||
| this.truckId = truckId | |||||
| this.truckDepartureTime = truckDepartureTime | |||||
| this.itemId = itemId | |||||
| this.shopId = shopId | |||||
| this.shopPoSupplierId = shopPoSupplierId | |||||
| this.handledBy = handledBy | |||||
| this.createdBy = createdBy | |||||
| this.modifiedBy = modifiedBy | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,21 @@ | |||||
| package com.ffii.fpsms.modules.deliveryOrder.entity | |||||
| import com.ffii.core.support.AbstractRepository | |||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfo | |||||
| import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderStatus | |||||
| import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus | |||||
| import com.ffii.fpsms.modules.master.entity.projections.SearchId | |||||
| import org.springframework.data.jpa.repository.JpaRepository | |||||
| import org.springframework.data.jpa.repository.Query | |||||
| import org.springframework.stereotype.Repository | |||||
| import java.io.Serializable | |||||
| import java.time.LocalDateTime | |||||
| @Repository | |||||
| interface DoPickOrderRepository : JpaRepository<DoPickOrder, Long> { | |||||
| fun findByTicketNoStartingWith(prefix: String): List<DoPickOrder> | |||||
| fun findByStoreIdAndTicketStatusOrderByTruckDepartureTimeAsc( | |||||
| storeId: String, | |||||
| status: DoPickOrderStatus | |||||
| ): List<DoPickOrder> | |||||
| } | |||||
| @@ -0,0 +1,6 @@ | |||||
| package com.ffii.fpsms.modules.deliveryOrder.enums | |||||
| enum class DoPickOrderStatus(val value: String) { | |||||
| pending("pending"), | |||||
| completed("completed") | |||||
| } | |||||
| @@ -29,7 +29,12 @@ import java.time.LocalDate | |||||
| import java.math.BigDecimal | import java.math.BigDecimal | ||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | import com.ffii.fpsms.modules.master.web.models.MessageResponse | ||||
| import java.time.LocalDateTime | import java.time.LocalDateTime | ||||
| import com.ffii.fpsms.modules.deliveryOrder.service.DoPickOrderService | |||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrder | |||||
| import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus | |||||
| import java.time.format.DateTimeFormatter | |||||
| import com.ffii.fpsms.modules.pickOrder.entity.TruckRepository | |||||
| import java.time.LocalTime | |||||
| @Service | @Service | ||||
| open class DeliveryOrderService( | open class DeliveryOrderService( | ||||
| private val deliveryOrderRepository: DeliveryOrderRepository, | private val deliveryOrderRepository: DeliveryOrderRepository, | ||||
| @@ -39,24 +44,27 @@ open class DeliveryOrderService( | |||||
| private val m18DataLogRepository: M18DataLogRepository, | private val m18DataLogRepository: M18DataLogRepository, | ||||
| private val userService: UserService, | private val userService: UserService, | ||||
| private val userRepository: UserRepository, | private val userRepository: UserRepository, | ||||
| private val pickOrderService: PickOrderService | |||||
| private val pickOrderService: PickOrderService, | |||||
| private val doPickOrderService: DoPickOrderService, | |||||
| private val truckRepository: TruckRepository | |||||
| ) { | ) { | ||||
| open fun findByM18DataLogId(m18DataLogId: Long): DeliveryOrder? { | open fun findByM18DataLogId(m18DataLogId: Long): DeliveryOrder? { | ||||
| return deliveryOrderRepository.findTopByM18DataLogIdAndDeletedIsFalseOrderByModifiedDesc(m18DataLogId) | return deliveryOrderRepository.findTopByM18DataLogIdAndDeletedIsFalseOrderByModifiedDesc(m18DataLogId) | ||||
| } | } | ||||
| open fun getDoList() : List<DeliveryOrderInfo> { | |||||
| open fun getDoList(): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findDeliveryOrderInfoByDeletedIsFalse(); | return deliveryOrderRepository.findDeliveryOrderInfoByDeletedIsFalse(); | ||||
| } | } | ||||
| /* | |||||
| /* | |||||
| open fun getDetailedDo(id: Long) : DeliveryOrder? { | open fun getDetailedDo(id: Long) : DeliveryOrder? { | ||||
| return deliveryOrderRepository.findByIdAndDeletedIsFalse(id); | return deliveryOrderRepository.findByIdAndDeletedIsFalse(id); | ||||
| } | } | ||||
| */ | */ | ||||
| open fun getDetailedDo(id: Long): DoDetailResponse? { | open fun getDetailedDo(id: Long): DoDetailResponse? { | ||||
| val deliveryOrder = deliveryOrderRepository.findByIdAndDeletedIsFalse(id) ?: return null | val deliveryOrder = deliveryOrderRepository.findByIdAndDeletedIsFalse(id) ?: return null | ||||
| return DoDetailResponse( | return DoDetailResponse( | ||||
| id = deliveryOrder.id!!, | id = deliveryOrder.id!!, | ||||
| code = deliveryOrder.code ?: "", | code = deliveryOrder.code ?: "", | ||||
| @@ -80,11 +88,12 @@ open class DeliveryOrderService( | |||||
| } | } | ||||
| ) | ) | ||||
| } | } | ||||
| open fun searchByCode(code: String?) : List<DeliveryOrderInfo> { | |||||
| open fun searchByCode(code: String?): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndDeletedIsFalse(code); | return deliveryOrderRepository.findAllByCodeContainsAndDeletedIsFalse(code); | ||||
| } | } | ||||
| open fun searchByShopName(shopName: String) : List<DeliveryOrderInfo> { | |||||
| open fun searchByShopName(shopName: String): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByShopNameContainsAndDeletedIsFalse(shopName); | return deliveryOrderRepository.findAllByShopNameContainsAndDeletedIsFalse(shopName); | ||||
| } | } | ||||
| @@ -97,41 +106,125 @@ open class DeliveryOrderService( | |||||
| } | } | ||||
| open fun getFullList(): List<DeliveryOrderInfo>{ | |||||
| open fun getFullList(): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllBy(); | return deliveryOrderRepository.findAllBy(); | ||||
| } | } | ||||
| open fun searchAll(code: String?, shopName: String?, status: DeliveryOrderStatus?, orderStartDate: LocalDateTime?, orderEndDate: LocalDateTime?, estArrStartDate: LocalDateTime?, estArrEndDate: LocalDateTime?):List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndStatusAndOrderDateBetweenAndEstimatedArrivalDateBetweenAndDeletedIsFalse(code, shopName, status, orderStartDate, orderEndDate, estArrStartDate, estArrEndDate); | |||||
| open fun searchAll( | |||||
| code: String?, | |||||
| shopName: String?, | |||||
| status: DeliveryOrderStatus?, | |||||
| orderStartDate: LocalDateTime?, | |||||
| orderEndDate: LocalDateTime?, | |||||
| estArrStartDate: LocalDateTime?, | |||||
| estArrEndDate: LocalDateTime? | |||||
| ): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndStatusAndOrderDateBetweenAndEstimatedArrivalDateBetweenAndDeletedIsFalse( | |||||
| code, | |||||
| shopName, | |||||
| status, | |||||
| orderStartDate, | |||||
| orderEndDate, | |||||
| estArrStartDate, | |||||
| estArrEndDate | |||||
| ); | |||||
| } | } | ||||
| open fun searchWithoutStatus(code: String?, shopName: String?, orderStartDate: LocalDateTime?, orderEndDate: LocalDateTime?, estArrStartDate: LocalDateTime?, estArrEndDate: LocalDateTime?) : List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndOrderDateBetweenAndEstimatedArrivalDateBetweenAndDeletedIsFalse(code, shopName, orderStartDate, orderEndDate, estArrStartDate, estArrEndDate); | |||||
| open fun searchWithoutStatus( | |||||
| code: String?, | |||||
| shopName: String?, | |||||
| orderStartDate: LocalDateTime?, | |||||
| orderEndDate: LocalDateTime?, | |||||
| estArrStartDate: LocalDateTime?, | |||||
| estArrEndDate: LocalDateTime? | |||||
| ): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndOrderDateBetweenAndEstimatedArrivalDateBetweenAndDeletedIsFalse( | |||||
| code, | |||||
| shopName, | |||||
| orderStartDate, | |||||
| orderEndDate, | |||||
| estArrStartDate, | |||||
| estArrEndDate | |||||
| ); | |||||
| } | } | ||||
| open fun searchWithoutEstArrDate(code: String?, shopName: String?, status: DeliveryOrderStatus?, orderStartDate: LocalDateTime?, orderEndDate: LocalDateTime?): List<DeliveryOrderInfo>{ | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndStatusAndOrderDateBetweenAndDeletedIsFalse(code, shopName, status, orderStartDate, orderEndDate); | |||||
| open fun searchWithoutEstArrDate( | |||||
| code: String?, | |||||
| shopName: String?, | |||||
| status: DeliveryOrderStatus?, | |||||
| orderStartDate: LocalDateTime?, | |||||
| orderEndDate: LocalDateTime? | |||||
| ): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndStatusAndOrderDateBetweenAndDeletedIsFalse( | |||||
| code, | |||||
| shopName, | |||||
| status, | |||||
| orderStartDate, | |||||
| orderEndDate | |||||
| ); | |||||
| } | } | ||||
| open fun searchWithoutEstArrDateAndStatus(code: String?, shopName: String?, orderStartDate: LocalDateTime?, orderEndDate: LocalDateTime?): List<DeliveryOrderInfo>{ | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndOrderDateBetweenAndDeletedIsFalse(code, shopName, orderStartDate, orderEndDate); | |||||
| open fun searchWithoutEstArrDateAndStatus( | |||||
| code: String?, | |||||
| shopName: String?, | |||||
| orderStartDate: LocalDateTime?, | |||||
| orderEndDate: LocalDateTime? | |||||
| ): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndOrderDateBetweenAndDeletedIsFalse( | |||||
| code, | |||||
| shopName, | |||||
| orderStartDate, | |||||
| orderEndDate | |||||
| ); | |||||
| } | } | ||||
| open fun searchWithoutOrderDate(code: String?, shopName: String?, status: DeliveryOrderStatus?, estArrStartDate: LocalDateTime?, estArrEndDate: LocalDateTime?) : List<DeliveryOrderInfo>{ | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndStatusAndEstimatedArrivalDateBetweenAndDeletedIsFalse(code, shopName, status, estArrStartDate, estArrEndDate); | |||||
| open fun searchWithoutOrderDate( | |||||
| code: String?, | |||||
| shopName: String?, | |||||
| status: DeliveryOrderStatus?, | |||||
| estArrStartDate: LocalDateTime?, | |||||
| estArrEndDate: LocalDateTime? | |||||
| ): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndStatusAndEstimatedArrivalDateBetweenAndDeletedIsFalse( | |||||
| code, | |||||
| shopName, | |||||
| status, | |||||
| estArrStartDate, | |||||
| estArrEndDate | |||||
| ); | |||||
| } | } | ||||
| open fun searchWithoutOrderDateAndStatus(code: String?, shopName: String?, estArrStartDate: LocalDateTime?, estArrEndDate: LocalDateTime?) : List<DeliveryOrderInfo>{ | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndEstimatedArrivalDateBetweenAndDeletedIsFalse(code, shopName, estArrStartDate, estArrEndDate); | |||||
| open fun searchWithoutOrderDateAndStatus( | |||||
| code: String?, | |||||
| shopName: String?, | |||||
| estArrStartDate: LocalDateTime?, | |||||
| estArrEndDate: LocalDateTime? | |||||
| ): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndEstimatedArrivalDateBetweenAndDeletedIsFalse( | |||||
| code, | |||||
| shopName, | |||||
| estArrStartDate, | |||||
| estArrEndDate | |||||
| ); | |||||
| } | } | ||||
| open fun searchWithoutDate(code: String?, shopName: String?, status: DeliveryOrderStatus?) : List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndStatusAndDeletedIsFalse(code, shopName, status); | |||||
| open fun searchWithoutDate( | |||||
| code: String?, | |||||
| shopName: String?, | |||||
| status: DeliveryOrderStatus? | |||||
| ): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndStatusAndDeletedIsFalse( | |||||
| code, | |||||
| shopName, | |||||
| status | |||||
| ); | |||||
| } | } | ||||
| open fun searchCodeAndShopName(code: String?, shopName: String?) : List<DeliveryOrderInfo> { | |||||
| open fun searchCodeAndShopName(code: String?, shopName: String?): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndDeletedIsFalse(code, shopName); | return deliveryOrderRepository.findAllByCodeContainsAndShopNameContainsAndDeletedIsFalse(code, shopName); | ||||
| } | } | ||||
| open fun updateDeliveryOrderStatus(request: SaveDeliveryOrderStatusRequest): SaveDeliveryOrderResponse { | open fun updateDeliveryOrderStatus(request: SaveDeliveryOrderStatusRequest): SaveDeliveryOrderResponse { | ||||
| val deliveryOrder = checkNotNull( | val deliveryOrder = checkNotNull( | ||||
| request.id?.let { deliveryOrderRepository.findById(it).getOrNull() } | request.id?.let { deliveryOrderRepository.findById(it).getOrNull() } | ||||
| @@ -212,9 +305,13 @@ open class DeliveryOrderService( | |||||
| @Transactional(rollbackFor = [Exception::class]) | @Transactional(rollbackFor = [Exception::class]) | ||||
| open fun releaseDeliveryOrder(request: ReleaseDoRequest): MessageResponse { | open fun releaseDeliveryOrder(request: ReleaseDoRequest): MessageResponse { | ||||
| println("�� DEBUG: Starting releaseDeliveryOrder for DO ID: ${request.id}, User ID: ${request.userId}") | |||||
| val deliveryOrder = deliveryOrderRepository.findByIdAndDeletedIsFalse(request.id) | val deliveryOrder = deliveryOrderRepository.findByIdAndDeletedIsFalse(request.id) | ||||
| ?: throw NoSuchElementException("Delivery Order not found") | ?: throw NoSuchElementException("Delivery Order not found") | ||||
| println("�� DEBUG: Found delivery order - ID: ${deliveryOrder.id}, Shop: ${deliveryOrder.shop?.code}, Status: ${deliveryOrder.status}") | |||||
| deliveryOrder.apply { | deliveryOrder.apply { | ||||
| status = DeliveryOrderStatus.PENDING | status = DeliveryOrderStatus.PENDING | ||||
| } | } | ||||
| @@ -228,13 +325,61 @@ open fun releaseDeliveryOrder(request: ReleaseDoRequest): MessageResponse { | |||||
| ) | ) | ||||
| } | } | ||||
| val po = SavePickOrderRequest( | val po = SavePickOrderRequest( | ||||
| doId = deliveryOrder.id, // Set doId instead of joId | |||||
| type = PickOrderType.DELIVERY_ORDER, // You might need to add this enum value | |||||
| doId = deliveryOrder.id, | |||||
| type = PickOrderType.DELIVERY_ORDER, | |||||
| targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now(), | targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now(), | ||||
| pickOrderLine = pols | pickOrderLine = pols | ||||
| ) | ) | ||||
| pickOrderService.create(po) | |||||
| val createdPickOrder = pickOrderService.create(po) | |||||
| println("🔍 DEBUG: Created pick order - ID: ${createdPickOrder.id}") | |||||
| // ✅ CREATE do_pick_order_record entries | |||||
| val targetDate = deliveryOrder.estimatedArrivalDate?.toLocalDate() ?: LocalDate.now() | |||||
| val datePrefix = targetDate.format(DateTimeFormatter.ofPattern("ddMMyy")) | |||||
| println("�� DEBUG: Target date: $targetDate, Date prefix: $datePrefix") | |||||
| // Get next ticket number for this date | |||||
| val nextTicketNumber = doPickOrderService.getNextTicketNumber(datePrefix) | |||||
| println("�� DEBUG: Next ticket number: $nextTicketNumber") | |||||
| // ✅ Find truck by shop ID with earliest departure time | |||||
| val truck = deliveryOrder.shop?.id?.let { shopId -> | |||||
| println("�� DEBUG: Looking for truck with shop ID: $shopId") | |||||
| val trucks = truckRepository.findByShopIdAndDeletedFalse(shopId) | |||||
| println("🔍 DEBUG: Found ${trucks.size} trucks for shop $shopId") | |||||
| trucks.forEach { t -> | |||||
| println("🔍 DEBUG: Truck ID: ${t.id}, DepartureTime: ${t.departureTime}") | |||||
| } | |||||
| val selectedTruck = trucks.minByOrNull { it.departureTime ?: LocalTime.MAX } | |||||
| println("🔍 DEBUG: Selected truck: ID=${selectedTruck?.id}, DepartureTime=${selectedTruck?.departureTime}") | |||||
| selectedTruck | |||||
| } | |||||
| println("🔍 DEBUG: Processing ${deliveryOrder.deliveryOrderLines.size} delivery order lines") | |||||
| deliveryOrder.deliveryOrderLines.forEach { line -> | |||||
| val storeId = if (deliveryOrder.shop?.code == "P06B") "2/F" else "4/F" | |||||
| println("�� DEBUG: Processing line - Item ID: ${line.item?.id}, Store ID: $storeId") | |||||
| val doPickOrder = DoPickOrder( | |||||
| storeId = storeId, | |||||
| ticketNo = nextTicketNumber, | |||||
| ticketStatus = DoPickOrderStatus.pending, | |||||
| truckId = truck?.id, | |||||
| truckDepartureTime = truck?.departureTime, | |||||
| itemId = line.item?.id, | |||||
| shopId = deliveryOrder.shop?.id, | |||||
| shopPoSupplierId = deliveryOrder.shop?.id, | |||||
| handledBy = request.userId | |||||
| ) | |||||
| println("�� DEBUG: Creating DoPickOrder - Store: $storeId, Ticket: $nextTicketNumber, Truck: ${truck?.id}") | |||||
| val savedDoPickOrder = doPickOrderService.save(doPickOrder) | |||||
| println("🔍 DEBUG: Saved DoPickOrder - ID: ${savedDoPickOrder.id}") | |||||
| } | |||||
| return MessageResponse( | return MessageResponse( | ||||
| id = deliveryOrder.id, | id = deliveryOrder.id, | ||||
| @@ -0,0 +1,95 @@ | |||||
| package com.ffii.fpsms.modules.deliveryOrder.service | |||||
| import com.ffii.fpsms.m18.entity.M18DataLogRepository | |||||
| import com.ffii.fpsms.m18.service.M18DataLogService | |||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrder | |||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrderRepository | |||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfo | |||||
| import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderStatus | |||||
| import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderRequest | |||||
| import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderResponse | |||||
| import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderStatusRequest | |||||
| import com.ffii.fpsms.modules.master.service.CurrencyService | |||||
| import com.ffii.fpsms.modules.master.service.ShopService | |||||
| import com.ffii.fpsms.modules.user.entity.UserRepository | |||||
| import com.ffii.fpsms.modules.user.service.UserService | |||||
| import org.springframework.stereotype.Service | |||||
| import org.springframework.transaction.annotation.Transactional | |||||
| import java.io.IOException | |||||
| import kotlin.jvm.optionals.getOrDefault | |||||
| import kotlin.jvm.optionals.getOrNull | |||||
| import com.ffii.fpsms.modules.deliveryOrder.web.models.DoDetailResponse | |||||
| import com.ffii.fpsms.modules.deliveryOrder.web.models.DoDetailLineResponse | |||||
| import com.ffii.fpsms.modules.deliveryOrder.web.models.ReleaseDoRequest | |||||
| import com.ffii.fpsms.modules.pickOrder.web.models.SavePickOrderRequest | |||||
| import com.ffii.fpsms.modules.pickOrder.web.models.SavePickOrderLineRequest | |||||
| import com.ffii.fpsms.modules.pickOrder.enums.PickOrderType | |||||
| import com.ffii.fpsms.modules.pickOrder.service.PickOrderService | |||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrder | |||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRepository | |||||
| import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus | |||||
| import java.time.LocalDate | |||||
| import java.math.BigDecimal | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| import java.time.LocalDateTime | |||||
| import com.ffii.fpsms.modules.deliveryOrder.web.models.AssignByStoreRequest | |||||
| @Service | |||||
| class DoPickOrderService( | |||||
| private val doPickOrderRepository: DoPickOrderRepository | |||||
| ) { | |||||
| fun getNextTicketNumber(datePrefix: String): String { | |||||
| println("🔍 DEBUG: Getting next ticket number for date prefix: $datePrefix") | |||||
| try { | |||||
| val todayTickets = doPickOrderRepository.findByTicketNoStartingWith("${datePrefix}_") | |||||
| println("🔍 DEBUG: Found ${todayTickets.size} existing tickets with prefix ${datePrefix}_") | |||||
| todayTickets.forEach { ticket -> | |||||
| println("�� DEBUG: Existing ticket: ${ticket.ticketNo}, Status: ${ticket.ticketStatus}") | |||||
| } | |||||
| val nextNumber = (todayTickets.size + 1).toString().padStart(3, '0') | |||||
| val ticketNumber = "${datePrefix}_${nextNumber}" | |||||
| println("🔍 DEBUG: Generated ticket number: $ticketNumber") | |||||
| return ticketNumber | |||||
| } catch (e: Exception) { | |||||
| println("❌ ERROR in getNextTicketNumber: ${e.message}") | |||||
| e.printStackTrace() | |||||
| throw e | |||||
| } | |||||
| } | |||||
| fun save(record: DoPickOrder): DoPickOrder { | |||||
| return doPickOrderRepository.save(record) | |||||
| } | |||||
| fun findByStoreIdOrderByTruckDepartureTime(storeId: String): List<DoPickOrder> { | |||||
| return doPickOrderRepository.findByStoreIdAndTicketStatusOrderByTruckDepartureTimeAsc( | |||||
| storeId, DoPickOrderStatus.pending | |||||
| ) | |||||
| } | |||||
| // Add these missing methods | |||||
| fun assignByStore(request: AssignByStoreRequest): MessageResponse { | |||||
| // TODO: Implement store-based assignment logic | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = null, | |||||
| message = "Store-based assignment not implemented yet", | |||||
| errorPosition = null, | |||||
| entity = null | |||||
| ) | |||||
| } | |||||
| fun releaseAssignedByStore(request: AssignByStoreRequest): MessageResponse { | |||||
| // TODO: Implement store-based release logic | |||||
| return MessageResponse( | |||||
| id = null, | |||||
| code = null, | |||||
| name = null, | |||||
| type = null, | |||||
| message = "Store-based release not implemented yet", | |||||
| errorPosition = null, | |||||
| entity = null | |||||
| ) | |||||
| } | |||||
| } | |||||
| @@ -51,50 +51,93 @@ class DeliveryOrderController( | |||||
| } | } | ||||
| @GetMapping("/search-orderdate/{start}&{end}") | @GetMapping("/search-orderdate/{start}&{end}") | ||||
| fun searchBetweenOrderDate(@PathVariable start: LocalDateTime?,@PathVariable end: LocalDateTime?): List<DeliveryOrderInfo> { | |||||
| fun searchBetweenOrderDate( | |||||
| @PathVariable start: LocalDateTime?, | |||||
| @PathVariable end: LocalDateTime? | |||||
| ): List<DeliveryOrderInfo> { | |||||
| return deliveryOrderService.searchBetweenOrderDate(start, end); | return deliveryOrderService.searchBetweenOrderDate(start, end); | ||||
| } | } | ||||
| @GetMapping("/search-DO/{code}&{shopName}&{status}&{orderStartDate}&{orderEndDate}&{estArrStartDate}&{estArrEndDate}") | @GetMapping("/search-DO/{code}&{shopName}&{status}&{orderStartDate}&{orderEndDate}&{estArrStartDate}&{estArrEndDate}") | ||||
| fun searchDO(@PathVariable code: String?, @PathVariable shopName: String?, @PathVariable status: DeliveryOrderStatus?, @PathVariable orderStartDate: LocalDateTime? , @PathVariable orderEndDate: LocalDateTime?, @PathVariable estArrStartDate: LocalDateTime?, @PathVariable estArrEndDate: LocalDateTime?): List<DeliveryOrderInfo>{ | |||||
| fun searchDO( | |||||
| @PathVariable code: String?, | |||||
| @PathVariable shopName: String?, | |||||
| @PathVariable status: DeliveryOrderStatus?, | |||||
| @PathVariable orderStartDate: LocalDateTime?, | |||||
| @PathVariable orderEndDate: LocalDateTime?, | |||||
| @PathVariable estArrStartDate: LocalDateTime?, | |||||
| @PathVariable estArrEndDate: LocalDateTime? | |||||
| ): List<DeliveryOrderInfo> { | |||||
| println("test"); | println("test"); | ||||
| if(code != null || shopName != null){ | |||||
| if(orderStartDate != null && orderEndDate != null && estArrStartDate != null && estArrEndDate != null){ | |||||
| if (status != null){ | |||||
| return deliveryOrderService.searchAll(code, shopName, status, orderStartDate, orderEndDate, estArrStartDate, estArrEndDate); | |||||
| if (code != null || shopName != null) { | |||||
| if (orderStartDate != null && orderEndDate != null && estArrStartDate != null && estArrEndDate != null) { | |||||
| if (status != null) { | |||||
| return deliveryOrderService.searchAll( | |||||
| code, | |||||
| shopName, | |||||
| status, | |||||
| orderStartDate, | |||||
| orderEndDate, | |||||
| estArrStartDate, | |||||
| estArrEndDate | |||||
| ); | |||||
| } else { | |||||
| return deliveryOrderService.searchWithoutStatus( | |||||
| code, | |||||
| shopName, | |||||
| orderStartDate, | |||||
| orderEndDate, | |||||
| estArrStartDate, | |||||
| estArrEndDate | |||||
| ); | |||||
| } | } | ||||
| else{ | |||||
| return deliveryOrderService.searchWithoutStatus(code, shopName, orderStartDate, orderEndDate, estArrStartDate, estArrEndDate); | |||||
| } | |||||
| } | |||||
| else{ | |||||
| if(orderStartDate == null && orderEndDate == null && estArrStartDate == null && estArrEndDate == null){ | |||||
| if(status != null){ | |||||
| } else { | |||||
| if (orderStartDate == null && orderEndDate == null && estArrStartDate == null && estArrEndDate == null) { | |||||
| if (status != null) { | |||||
| return deliveryOrderService.searchWithoutDate(code, shopName, status); | return deliveryOrderService.searchWithoutDate(code, shopName, status); | ||||
| } | |||||
| else{ | |||||
| } else { | |||||
| return deliveryOrderService.searchCodeAndShopName(code, shopName); | return deliveryOrderService.searchCodeAndShopName(code, shopName); | ||||
| } | } | ||||
| } | |||||
| else{ | |||||
| if(estArrStartDate != null && estArrEndDate != null && (orderStartDate == null && orderEndDate == null)){ | |||||
| if (status != null){ | |||||
| return deliveryOrderService.searchWithoutOrderDate(code, shopName, status, estArrStartDate, estArrEndDate); | |||||
| } | |||||
| else{ | |||||
| return deliveryOrderService.searchWithoutOrderDateAndStatus(code, shopName, estArrStartDate, estArrEndDate); | |||||
| } | |||||
| } | |||||
| else if(orderStartDate != null && orderEndDate != null && (estArrStartDate == null && estArrEndDate == null)){ | |||||
| if (status != null){ | |||||
| return deliveryOrderService.searchAll(code, shopName, status, orderStartDate, orderEndDate, estArrStartDate, estArrEndDate); | |||||
| } else { | |||||
| if (estArrStartDate != null && estArrEndDate != null && (orderStartDate == null && orderEndDate == null)) { | |||||
| if (status != null) { | |||||
| return deliveryOrderService.searchWithoutOrderDate( | |||||
| code, | |||||
| shopName, | |||||
| status, | |||||
| estArrStartDate, | |||||
| estArrEndDate | |||||
| ); | |||||
| } else { | |||||
| return deliveryOrderService.searchWithoutOrderDateAndStatus( | |||||
| code, | |||||
| shopName, | |||||
| estArrStartDate, | |||||
| estArrEndDate | |||||
| ); | |||||
| } | } | ||||
| else{ | |||||
| return deliveryOrderService.searchWithoutStatus(code, shopName, orderStartDate, orderEndDate, estArrStartDate, estArrEndDate); | |||||
| } else if (orderStartDate != null && orderEndDate != null && (estArrStartDate == null && estArrEndDate == null)) { | |||||
| if (status != null) { | |||||
| return deliveryOrderService.searchAll( | |||||
| code, | |||||
| shopName, | |||||
| status, | |||||
| orderStartDate, | |||||
| orderEndDate, | |||||
| estArrStartDate, | |||||
| estArrEndDate | |||||
| ); | |||||
| } else { | |||||
| return deliveryOrderService.searchWithoutStatus( | |||||
| code, | |||||
| shopName, | |||||
| orderStartDate, | |||||
| orderEndDate, | |||||
| estArrStartDate, | |||||
| estArrEndDate | |||||
| ); | |||||
| } | } | ||||
| } | |||||
| else{ | |||||
| } else { | |||||
| return emptyList(); | return emptyList(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -104,14 +147,9 @@ class DeliveryOrderController( | |||||
| return deliveryOrderService.getFullList(); | return deliveryOrderService.getFullList(); | ||||
| } | } | ||||
| @PostMapping("/update-status") | @PostMapping("/update-status") | ||||
| fun updateDoStatus(@RequestBody request: SaveDeliveryOrderStatusRequest): SaveDeliveryOrderResponse { | fun updateDoStatus(@RequestBody request: SaveDeliveryOrderStatusRequest): SaveDeliveryOrderResponse { | ||||
| return deliveryOrderService.updateDeliveryOrderStatus(request); | return deliveryOrderService.updateDeliveryOrderStatus(request); | ||||
| @@ -125,8 +163,10 @@ class DeliveryOrderController( | |||||
| ) | ) | ||||
| return deliveryOrderService.updateDeliveryOrderStatus(request); | return deliveryOrderService.updateDeliveryOrderStatus(request); | ||||
| } | } | ||||
| @PostMapping("/release") | @PostMapping("/release") | ||||
| fun releaseDeliveryOrder(@Valid @RequestBody request: ReleaseDoRequest): MessageResponse { | |||||
| fun releaseDeliveryOrder(@RequestBody request: ReleaseDoRequest): MessageResponse { | |||||
| // ✅ Simply pass the request directly - userId comes from frontend session | |||||
| return deliveryOrderService.releaseDeliveryOrder(request) | return deliveryOrderService.releaseDeliveryOrder(request) | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,53 @@ | |||||
| package com.ffii.fpsms.modules.deliveryOrder.web | |||||
| import com.ffii.core.response.RecordsRes | |||||
| import com.ffii.core.utils.CriteriaArgsBuilder | |||||
| import com.ffii.core.utils.PagingUtils | |||||
| import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||||
| import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository | |||||
| import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderInfo | |||||
| import com.ffii.fpsms.modules.pickOrder.service.PickOrderService | |||||
| import com.ffii.fpsms.modules.pickOrder.web.models.* | |||||
| import com.ffii.fpsms.modules.pickOrder.web.models.ConsoPickOrderRequest | |||||
| import com.ffii.fpsms.modules.pickOrder.web.models.ConsoPickOrderResponse | |||||
| import com.ffii.fpsms.modules.pickOrder.web.models.ReleaseConsoPickOrderRequest | |||||
| import com.ffii.fpsms.modules.pickOrder.web.models.SearchPickOrderRequest | |||||
| import com.ffii.fpsms.modules.pickOrder.web.models.SavePickOrderGroupRequest | |||||
| import jakarta.servlet.http.HttpServletRequest | |||||
| import jakarta.validation.Valid | |||||
| import org.springframework.data.domain.Page | |||||
| import org.springframework.data.domain.PageRequest | |||||
| import org.springframework.data.domain.Pageable | |||||
| import org.springframework.http.ResponseEntity | |||||
| import org.springframework.web.bind.annotation.GetMapping | |||||
| import org.springframework.web.bind.annotation.ModelAttribute | |||||
| import org.springframework.web.bind.annotation.PathVariable | |||||
| import org.springframework.web.bind.annotation.PostMapping | |||||
| import org.springframework.web.bind.annotation.RequestBody | |||||
| import org.springframework.web.bind.annotation.RequestMapping | |||||
| import org.springframework.web.bind.annotation.RequestParam | |||||
| import org.springframework.web.bind.annotation.RestController | |||||
| import java.time.DateTimeException | |||||
| import java.time.LocalDateTime | |||||
| import java.time.format.DateTimeFormatter | |||||
| import java.time.LocalDate | |||||
| import com.ffii.fpsms.modules.deliveryOrder.service.DoPickOrderService | |||||
| import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRepository | |||||
| import com.ffii.fpsms.modules.deliveryOrder.web.models.AssignByStoreRequest | |||||
| @RestController | |||||
| @RequestMapping("/doPickOrder") | |||||
| class DoPickOrderController( | |||||
| private val doPickOrderService: DoPickOrderService, | |||||
| private val doPickOrderRepository: DoPickOrderRepository, | |||||
| ) { | |||||
| @PostMapping("/assign-by-store") | |||||
| fun assignPickOrderByStore(@RequestBody request: AssignByStoreRequest): MessageResponse { | |||||
| return doPickOrderService.assignByStore(request) | |||||
| } | |||||
| @PostMapping("/release-assigned-by-store") | |||||
| fun releaseAssignedPickOrderByStore(@RequestBody request: AssignByStoreRequest): MessageResponse { | |||||
| return doPickOrderService.releaseAssignedByStore(request) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,6 @@ | |||||
| package com.ffii.fpsms.modules.deliveryOrder.web.models | |||||
| data class AssignByStoreRequest( | |||||
| val storeId: String, // "2/F" or "4/F" | |||||
| val assignTo: Long | |||||
| ) | |||||
| @@ -1,5 +1,6 @@ | |||||
| package com.ffii.fpsms.modules.deliveryOrder.web.models | package com.ffii.fpsms.modules.deliveryOrder.web.models | ||||
| data class ReleaseDoRequest( | data class ReleaseDoRequest( | ||||
| val id: Long | |||||
| val id: Long, | |||||
| val userId: Long | |||||
| ) | ) | ||||
| @@ -0,0 +1,63 @@ | |||||
| --liquibase formatted sql | |||||
| --changeset enson:update | |||||
| CREATE TABLE `do_pick_order` ( | |||||
| `id` int NOT NULL AUTO_INCREMENT, | |||||
| `store_id` varchar(10) NOT NULL, | |||||
| `ticket_no` varchar(50) NOT NULL, | |||||
| `ticket_status` enum('pending','completed') DEFAULT 'pending', | |||||
| `truck_id` int NOT NULL, | |||||
| `truck_departure_time` TIME NOT NULL, | |||||
| `item_id` int NOT NULL, | |||||
| `shop_id` int DEFAULT NULL, | |||||
| `shop_po_supplier_id` int NOT NULL, | |||||
| `handled_by` int NOT NULL, | |||||
| `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| `createdBy` varchar(30) DEFAULT NULL, | |||||
| `version` int NOT NULL DEFAULT '0', | |||||
| `modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| `modifiedBy` varchar(30) DEFAULT NULL, | |||||
| `deleted` tinyint(1) NOT NULL DEFAULT '0', | |||||
| PRIMARY KEY (`id`), | |||||
| KEY `IDX_DO_PICK_ORDER_TRUCK` (`truck_id`), | |||||
| KEY `IDX_DO_PICK_ORDER_ITEM` (`item_id`), | |||||
| KEY `IDX_DO_PICK_ORDER_SHOP` (`shop_id`), | |||||
| KEY `IDX_DO_PICK_ORDER_SHOP_SUPP` (`shop_po_supplier_id`), | |||||
| KEY `IDX_DO_PICK_ORDER_HANDLED_BY` (`handled_by`), | |||||
| CONSTRAINT `FK_DO_PICK_ORDER_ON_HANDLED_BY` FOREIGN KEY (`handled_by`) REFERENCES `user` (`id`), | |||||
| CONSTRAINT `FK_DO_PICK_ORDER_ON_ITEM` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`), | |||||
| CONSTRAINT `FK_DO_PICK_ORDER_ON_SHOP` FOREIGN KEY (`shop_id`) REFERENCES `shop` (`id`), | |||||
| CONSTRAINT `FK_DO_PICK_ORDER_ON_SHOP_PO_SUPPLIER` FOREIGN KEY (`shop_po_supplier_id`) REFERENCES `shop` (`id`), | |||||
| CONSTRAINT `FK_DO_PICK_ORDER_ON_TRUCK` FOREIGN KEY (`truck_id`) REFERENCES `Truck` (`id`) | |||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; | |||||
| CREATE TABLE `do_pick_order_record` ( | |||||
| `id` int NOT NULL AUTO_INCREMENT, | |||||
| `store_id` varchar(10) NOT NULL, | |||||
| `ticket_no` varchar(50) NOT NULL, | |||||
| `ticket_status` enum('pending','completed') DEFAULT 'pending', | |||||
| `truck_id` int NOT NULL, | |||||
| `truck_departure_time` TIME NOT NULL, | |||||
| `item_id` int NOT NULL, | |||||
| `shop_id` int DEFAULT NULL, | |||||
| `shop_po_supplier_id` int NOT NULL, | |||||
| `handled_by` int NOT NULL, | |||||
| `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| `createdBy` varchar(30) DEFAULT NULL, | |||||
| `version` int NOT NULL DEFAULT '0', | |||||
| `modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
| `modifiedBy` varchar(30) DEFAULT NULL, | |||||
| `deleted` tinyint(1) NOT NULL DEFAULT '0', | |||||
| PRIMARY KEY (`id`), | |||||
| KEY `IDX_DO_PICK_ORDER_REC_TRUCK` (`truck_id`), | |||||
| KEY `IDX_DO_PICK_ORDER_REC_ITEM` (`item_id`), | |||||
| KEY `IDX_DO_PICK_ORDER_REC_SHOP` (`shop_id`), | |||||
| KEY `IDX_DO_PICK_ORDER_REC_SHOP_SUPP` (`shop_po_supplier_id`), | |||||
| KEY `IDX_DO_PICK_ORDER_REC_HANDLED_BY` (`handled_by`), | |||||
| CONSTRAINT `FK_DO_PICK_ORDER_REC_ON_HANDLED_BY` FOREIGN KEY (`handled_by`) REFERENCES `user` (`id`), | |||||
| CONSTRAINT `FK_DO_PICK_ORDER_REC_ON_ITEM` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`), | |||||
| CONSTRAINT `FK_DO_PICK_ORDER_REC_ON_SHOP` FOREIGN KEY (`shop_id`) REFERENCES `shop` (`id`), | |||||
| CONSTRAINT `FK_DO_PICK_ORDER_REC_ON_SHOP_PO_SUPPLIER` FOREIGN KEY (`shop_po_supplier_id`) REFERENCES `shop` (`id`), | |||||
| CONSTRAINT `FK_DO_PICK_ORDER_REC_ON_TRUCK` FOREIGN KEY (`truck_id`) REFERENCES `Truck` (`id`) | |||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; | |||||