From 82c3e50a1a1768c09ba65844aacb45908a4b7d6e Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Thu, 28 Aug 2025 12:36:40 +0800 Subject: [PATCH] update --- .../modules/master/service/ItemsService.kt | 4 +- .../pickOrder/entity/PickOrderGroup.kt | 29 ++++ .../entity/PickOrderGroupRepository.kt | 42 ++++++ .../entity/projection/PickOrderGroupInfo.kt | 15 ++ .../pickOrder/service/PickOrderService.kt | 140 +++++++++++++++++- .../pickOrder/web/PickOrderController.kt | 71 ++++++++- .../web/models/ConsoPickOrderResponse.kt | 1 + .../web/models/SavePickOrderGroupRequest.kt | 12 ++ .../01_create_pick_order_group.sql | 20 +++ 9 files changed, 324 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderGroup.kt create mode 100644 src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderGroupRepository.kt create mode 100644 src/main/java/com/ffii/fpsms/modules/pickOrder/entity/projection/PickOrderGroupInfo.kt create mode 100644 src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/SavePickOrderGroupRequest.kt create mode 100644 src/main/resources/db/changelog/changes/20250825_01_enson/01_create_pick_order_group.sql diff --git a/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt b/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt index 9dae6fe..cbd89a2 100644 --- a/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt +++ b/src/main/java/com/ffii/fpsms/modules/master/service/ItemsService.kt @@ -82,11 +82,13 @@ open class ItemsService( po.targetDate, po.status, po.consoCode, - po.assignTo + po.assignTo, + COALESCE(pog.name, 'No Group') as groupName FROM pick_order po JOIN pick_order_line pol ON pol.poId = po.id JOIN items i ON i.id = pol.itemId LEFT JOIN uom_conversion uc ON uc.id = pol.uomId + LEFT JOIN pick_order_group pog ON pog.pick_order_id = po.id AND pog.deleted = false LEFT JOIN ( SELECT il.itemId, diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderGroup.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderGroup.kt new file mode 100644 index 0000000..0262bea --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderGroup.kt @@ -0,0 +1,29 @@ +package com.ffii.fpsms.modules.pickOrder.entity + +import com.ffii.core.entity.BaseEntity +import com.ffii.fpsms.modules.user.entity.User +import jakarta.persistence.* +import jakarta.validation.constraints.NotNull +import jakarta.validation.constraints.Size +import java.time.LocalDate + +@Entity +@Table(name = "pick_order_group") +open class PickOrderGroup: BaseEntity() { + + + @Column(name = "pick_order_id") + open var pickOrderId: Long? = null + + @Size(max = 50) + + @Column(name = "name") + open var name: String? = null + + @Column(name = "target_date") + open var targetDate: LocalDate? = null + + @ManyToOne + @JoinColumn(name = "releasedBy", referencedColumnName = "id") + open var releasedBy: User? = null +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderGroupRepository.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderGroupRepository.kt new file mode 100644 index 0000000..4d0867a --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/PickOrderGroupRepository.kt @@ -0,0 +1,42 @@ +package com.ffii.fpsms.modules.pickOrder.entity + +import com.ffii.core.support.AbstractRepository +import org.springframework.stereotype.Repository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param +import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderGroupInfo + +@Repository +interface PickOrderGroupRepository : AbstractRepository { + + @Query(""" + SELECT pog FROM PickOrderGroup pog + WHERE pog.deleted = false + ORDER BY pog.name DESC + """) + fun findTopByOrderByNameDesc(): PickOrderGroup? + + @Query(""" + SELECT pog FROM PickOrderGroup pog + WHERE pog.pickOrderId = :pickOrderId + AND pog.deleted = false + """) + fun findByPickOrderIdAndDeletedIsFalse(@Param("pickOrderId") pickOrderId: Long): List + @Query(""" + SELECT pog FROM PickOrderGroup pog + WHERE pog.pickOrderId IN :pickOrderIds + AND pog.deleted = false +""") +fun findByPickOrderIdInAndDeletedIsFalse(@Param("pickOrderIds") pickOrderIds: List): List + @Query(""" + SELECT pog FROM PickOrderGroup pog + WHERE pog.name = :name + AND pog.deleted = false + """) + fun findByNameAndDeletedIsFalse(@Param("name") name: String): PickOrderGroup? + @Query(""" + SELECT pog FROM PickOrderGroup pog + WHERE pog.deleted = false + """) + fun findAllByDeletedIsFalse(): List +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/projection/PickOrderGroupInfo.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/projection/PickOrderGroupInfo.kt new file mode 100644 index 0000000..1a0bb54 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/entity/projection/PickOrderGroupInfo.kt @@ -0,0 +1,15 @@ +package com.ffii.fpsms.modules.pickOrder.entity.projection + +import org.springframework.beans.factory.annotation.Value +import java.time.LocalDate + + + +interface PickOrderGroupInfo { + val id: Long? + val name: String? + val targetDate: LocalDate? + val pickOrderId: Long? + + +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt index a9ff50a..3fb8007 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/service/PickOrderService.kt @@ -16,6 +16,8 @@ import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderInfo import com.ffii.fpsms.modules.pickOrder.enums.PickOrderLineStatus import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus +import com.ffii.fpsms.modules.pickOrder.entity.PickOrderGroup +import com.ffii.fpsms.modules.pickOrder.entity.PickOrderGroupRepository import com.ffii.fpsms.modules.pickOrder.web.models.* import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository import com.ffii.fpsms.modules.stock.entity.StockOut @@ -44,6 +46,7 @@ import java.time.LocalDate import java.time.LocalDateTime import java.time.format.DateTimeFormatter import kotlin.jvm.optionals.getOrNull +import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderGroupInfo @Service open class PickOrderService( @@ -54,6 +57,7 @@ open class PickOrderService( private val userService: UserService, private val stockOutLIneRepository: StockOutLIneRepository, private val inventoryLotLineRepository: InventoryLotLineRepository, + private val pickOrderGroupRepository: PickOrderGroupRepository, private val inventoryLotLineService: InventoryLotLineService, private val inventoryService: InventoryService, private val stockOutRepository: StockOutRepository, @@ -152,7 +156,8 @@ open class PickOrderService( // Get full pick orders with relationships val fullPickOrders = pickOrderRepository.findAllByIdIn(pickOrderIds) - + val groupsByPickOrderId = pickOrderGroupRepository.findByPickOrderIdInAndDeletedIsFalse(pickOrderIds) + .groupBy { it.pickOrderId } // Get all item IDs val itemIds = fullPickOrders .flatMap { it.pickOrderLines } @@ -191,7 +196,9 @@ open class PickOrderService( suggestedList = emptyList() // Empty list since you don't need suggestions ) } - + val groupName = po.id?.let { pickOrderId -> + groupsByPickOrderId[pickOrderId]?.firstOrNull()?.name + } ?: "No Group" GetPickOrderInfo( id = po.id, code = po.code, @@ -199,6 +206,7 @@ open class PickOrderService( type = po.type?.value, status = po.status?.value, assignTo = po.assignTo?.id, + groupName = groupName, pickOrderLines = pickOrderLineInfos ) } @@ -644,6 +652,8 @@ open class PickOrderService( val one = BigDecimal.ONE val pos = pickOrderRepository.findAllByIdIn(ids) println(pos) + val groupsByPickOrderId = pickOrderGroupRepository.findByPickOrderIdInAndDeletedIsFalse(ids) + .groupBy { it.pickOrderId } // Get Inventory Data val requiredItems = pos .flatMap { it.pickOrderLines } @@ -698,7 +708,9 @@ open class PickOrderService( ) // } } - + val groupName = po.id?.let { pickOrderId -> + groupsByPickOrderId[pickOrderId]?.firstOrNull()?.name + } ?: "No Group" // Return GetPickOrderInfo( id = po.id, @@ -707,6 +719,7 @@ open class PickOrderService( type = po.type?.value, status = po.status?.value, assignTo = po.assignTo?.id, + groupName = groupName, pickOrderLines = releasePickOrderLineInfos ) } @@ -873,7 +886,7 @@ open class PickOrderService( il.lotNo, il.expiryDate, w.name as location, - COALESCE(uc.code, 'N/A') as stockUnit, + COALESCE(uc.udfudesc, 'N/A') as stockUnit, (COALESCE(ill.inQty, 0) - COALESCE(ill.outQty, 0) - COALESCE(ill.holdQty, 0)) as availableQty, spl.qty as requiredQty, COALESCE(sol.qty, 0) as actualPickQty, @@ -1092,12 +1105,127 @@ open class PickOrderService( } else { return MessageResponse( id = stockOut.id, - name = stockOut.consoPickOrderCode ?: stockOut.deliveryOrderCode, // 修复:使用 stockOut 而不是 savedStockOut - code = stockOut.consoPickOrderCode ?: stockOut.deliveryOrderCode, // 修复:使用 stockOut 而不是 savedStockOut + name = stockOut.consoPickOrderCode ?: stockOut.deliveryOrderCode, + code = stockOut.consoPickOrderCode ?: stockOut.deliveryOrderCode, type = stockOut.type, message = "not completed", errorPosition = null, ) } } + + + open fun createGroup(name: String, targetDate: LocalDate, pickOrderId: Long?): PickOrderGroup { + val group = PickOrderGroup().apply { + this.name = name + this.targetDate = targetDate + this.pickOrderId = pickOrderId + } + return pickOrderGroupRepository.save(group) + } + + fun getGroupsByPickOrderId(pickOrderId: Long): List { + return pickOrderGroupRepository.findByPickOrderIdAndDeletedIsFalse(pickOrderId) + } + + fun getAllGroupsFromDatabase(): List> { + val sql = """ + SELECT id, name, target_date, pick_order_id + FROM pick_order_group + WHERE deleted = false + ORDER BY name ASC + """.trimIndent() + + return jdbcDao.queryForList(sql, emptyMap()) + } + + open fun allPickOrdersGroup(): List { + return pickOrderGroupRepository.findAllByDeletedIsFalse() + } + open fun getLatestGroupNameAndCreate(): MessageResponse { + // Use the working repository method like the old /latest endpoint + val allGroups = allPickOrdersGroup() + val nextGroupName = if (allGroups.isNotEmpty()) { + // Sort by numeric part of the name (A001 -> 1, A006 -> 6) + val latestName = allGroups + .filter { it.name?.startsWith("A") == true } + .maxByOrNull { group -> + group.name?.substring(1)?.toIntOrNull() ?: 0 + }?.name ?: "A000" + + // Generate next group name + val currentNumber = latestName.substring(1).toIntOrNull() ?: 0 + val nextNumber = currentNumber + 1 + "A${nextNumber.toString().padStart(3, '0')}" + } else { + "A001" // If no groups exist, return A001 + } + + // Use the new flexible createNewGroups method + val request = SavePickOrderGroupRequest( + names = listOf(nextGroupName), // Create new group with the generated name + targetDate = null, + pickOrderId = null + ) + + return createNewGroups(request) + } + + fun getLatestGroupName(): String { + // Use allPickOrdersGroup() instead of the failing repository method + val allGroups = allPickOrdersGroup() + return if (allGroups.isNotEmpty()) { + // Sort by numeric part of the name (A001 -> 1, A006 -> 6) + val latestName = allGroups + .filter { it.name?.startsWith("A") == true } + .maxByOrNull { group -> + group.name?.substring(1)?.toIntOrNull() ?: 0 + }?.name ?: "A000" + + // Generate next group name + val currentNumber = latestName.substring(1).toIntOrNull() ?: 0 + val nextNumber = currentNumber + 1 + "A${nextNumber.toString().padStart(3, '0')}" + } else { + "A001" // If no groups exist, return A001 + } + } + open fun createNewGroups(request: SavePickOrderGroupRequest): MessageResponse { + val updatedGroups = mutableListOf() + val createdGroups = mutableListOf() + + // Case 1: Update existing groups by IDs + request.groupIds?.forEach { groupId -> + val group = pickOrderGroupRepository.findById(groupId).orElse(null) + if (group != null) { + group.targetDate = request.targetDate + group.pickOrderId = request.pickOrderId + val savedGroup = pickOrderGroupRepository.save(group) + updatedGroups.add(savedGroup) + } + } + + // Case 2: Create new groups by names + request.names?.forEach { name -> + val group = PickOrderGroup().apply { + this.name = name + this.targetDate = request.targetDate + this.pickOrderId = request.pickOrderId + } + val savedGroup = pickOrderGroupRepository.save(group) + createdGroups.add(savedGroup) + } + + val totalGroups = updatedGroups.size + createdGroups.size + val allGroups = updatedGroups + createdGroups + + return MessageResponse( + id = allGroups.firstOrNull()?.id, + name = allGroups.map { it.name ?: "" }.joinToString(", "), + code = "groups_processed", + type = "pick_order_groups", + message = "Updated ${updatedGroups.size} groups and created ${createdGroups.size} groups successfully", + errorPosition = "", + ) + } } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt index 9b6db8a..a7f3c9a 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/PickOrderController.kt @@ -12,6 +12,7 @@ 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 @@ -29,6 +30,8 @@ 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.pickOrder.entity.projection.PickOrderGroupInfo @RestController @RequestMapping("/pickOrder") @@ -45,11 +48,12 @@ class PickOrderController( fun allPickOrdersByPage(@ModelAttribute request: SearchPickOrderRequest): RecordsRes { return pickOrderService.allPickOrdersByPage(request); } - + @GetMapping("/getRecordByPageWithStock") fun getPickOrdersWithStockBalanceByPage(@ModelAttribute request: SearchPickOrderRequest): RecordsRes { return pickOrderService.getPickOrdersWithStockBalanceByPage(request); } + @GetMapping("/getRecordByPage-conso") fun allConsoPickOrdersByPage(request: HttpServletRequest): RecordsRes> { val criteriaArgs = CriteriaArgsBuilder.withRequest(request) @@ -60,9 +64,10 @@ class PickOrderController( val pageSize = request.getParameter("pageSize")?.toIntOrNull() ?: 10 // Default to 10 if not provided val pageNum = request.getParameter("pageNum")?.toIntOrNull() ?: 1 // Default to 1 if not provided val fullList = pickOrderService.getConsoPickOrderList(criteriaArgs) - val paginatedList = PagingUtils.getPaginatedList(fullList,pageSize, pageNum) + val paginatedList = PagingUtils.getPaginatedList(fullList, pageSize, pageNum) return RecordsRes(paginatedList, fullList.size) } + @PostMapping("/assign") fun assignPickOrders(@RequestBody request: Map): MessageResponse { val pickOrderIds = (request["pickOrderIds"] as List<*>).map { it.toString().toLong() } @@ -77,6 +82,7 @@ class PickOrderController( val assignTo = request["assignTo"].toString().toLong() return pickOrderService.releasePickOrders(pickOrderIds, assignTo) } + @GetMapping("/get-pickorder-line-byPage") fun getPickOrderLine(request: HttpServletRequest): RecordsRes> { val criteriaArgs = CriteriaArgsBuilder.withRequest(request) @@ -85,7 +91,7 @@ class PickOrderController( val pageSize = request.getParameter("pageSize")?.toIntOrNull() ?: 10 // Default to 10 if not provided val pageNum = request.getParameter("pageNum")?.toIntOrNull() ?: 1 // Default to 1 if not provided val fullList = pickOrderService.getPickOrderLine(criteriaArgs) - val paginatedList = PagingUtils.getPaginatedList(fullList,pageSize, pageNum) + val paginatedList = PagingUtils.getPaginatedList(fullList, pageSize, pageNum) return RecordsRes(paginatedList, fullList.size) } @@ -121,16 +127,19 @@ class PickOrderController( fun getAllPickOrdersInfo(): GetPickOrderInfoResponse { return pickOrderService.getAllPickOrdersInfo(); } + @PostMapping("/releaseConso") fun releaseConsoPickOrderAction(@Valid @RequestBody request: ReleaseConsoPickOrderRequest): ReleasePickOrderInfoResponse { return pickOrderService.releaseConsoPickOrderAction(request) } + @PostMapping("/release-assigned") fun releaseAssignedPickOrders(@RequestBody request: Map): MessageResponse { val pickOrderIds = (request["pickOrderIds"] as List<*>).map { it.toString().toLong() } val assignTo = request["assignTo"].toString().toLong() return pickOrderService.releaseAssignedPickOrders(pickOrderIds, assignTo) } + // Start Pick Order @GetMapping("/pickConso/{consoCode}") fun pickConsoPickOrderInfo(@PathVariable consoCode: String): ReleasePickOrderInfoResponse { @@ -153,4 +162,60 @@ class PickOrderController( } + @PostMapping("/groups") + fun createGroup(@RequestBody request: Map): ResponseEntity> { + println("request: $request") + val name = request["name"] as String + val targetDateStr = request["targetDate"] as String + val targetDate = LocalDate.parse(targetDateStr) + val pickOrderId = when (val value = request["pickOrderId"]) { + is Int -> value.toLong() + is Long -> value + is String -> value.toLongOrNull() + else -> null + } + println("name: $name") + println("targetDate: $targetDate") + println("pickOrderId: $pickOrderId") + val group = pickOrderService.createGroup(name, targetDate, pickOrderId) + return ResponseEntity.ok( + mapOf( + "id" to (group.id ?: 0L), + "name" to (group.name ?: ""), + "targetDate" to (group.targetDate?.toString() ?: ""), + "pickOrderId" to (group.pickOrderId ?: 0L) + ) + ) + //println("Response: $response") + } + + @GetMapping("/groups/{pickOrderId}") + fun getGroupsByPickOrder(@PathVariable pickOrderId: Long): ResponseEntity>> { + val groups = pickOrderService.getGroupsByPickOrderId(pickOrderId) + val response = groups.map { group -> + mapOf( + "id" to (group.id ?: 0L), + "name" to (group.name ?: ""), + "targetDate" to (group.targetDate?.toString() ?: ""), + "pickOrderId" to (group.pickOrderId ?: 0L) + ) + } + return ResponseEntity.ok(response) + + + + } + @GetMapping("/groups/latest") + fun getLatestGroupName(): MessageResponse { + return pickOrderService.getLatestGroupNameAndCreate() + } + @GetMapping("/groups/list") + fun getAllGroups(): List { + return pickOrderService.allPickOrdersGroup() + } + @PostMapping("/groups/create") + fun createNewGroups(@Valid @RequestBody request: SavePickOrderGroupRequest): MessageResponse { + return pickOrderService.createNewGroups(request) + } + } \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/ConsoPickOrderResponse.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/ConsoPickOrderResponse.kt index efb7d1a..4677edf 100644 --- a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/ConsoPickOrderResponse.kt +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/ConsoPickOrderResponse.kt @@ -35,6 +35,7 @@ data class GetPickOrderInfo( val type: String?, val status: String?, val assignTo: Long?, + val groupName: String?, val pickOrderLines: List ) diff --git a/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/SavePickOrderGroupRequest.kt b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/SavePickOrderGroupRequest.kt new file mode 100644 index 0000000..3d873e5 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/pickOrder/web/models/SavePickOrderGroupRequest.kt @@ -0,0 +1,12 @@ +package com.ffii.fpsms.modules.pickOrder.web.models + +import java.time.LocalDate + + +data class SavePickOrderGroupRequest ( + val groupIds: List? = null, + val names: List? = null, + val targetDate: LocalDate?=null, + val pickOrderId: Long? = null +) + diff --git a/src/main/resources/db/changelog/changes/20250825_01_enson/01_create_pick_order_group.sql b/src/main/resources/db/changelog/changes/20250825_01_enson/01_create_pick_order_group.sql new file mode 100644 index 0000000..86a67df --- /dev/null +++ b/src/main/resources/db/changelog/changes/20250825_01_enson/01_create_pick_order_group.sql @@ -0,0 +1,20 @@ +-- liquibase formatted sql +-- changeset cyril:create pick order + +CREATE TABLE `pick_order_group` +( + `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', + `pick_order_id` INT , + `name` VARCHAR(50) NOT NULL UNIQUE, + `target_date` DATE NOT NULL, + `releasedBy` INT NULL, + CONSTRAINT pk_pick_order_group PRIMARY KEY (id), + CONSTRAINT `FK_PICK_ORDER_GROUP_ON_PICK_ORDER_ID` FOREIGN KEY (`pick_order_id`) REFERENCES `pick_order` (`id`), + CONSTRAINT `FK_PICK_ORDER_GROUP_ON_RELEASEDBY` FOREIGN KEY (`releasedBy`) REFERENCES `user` (`id`) +); \ No newline at end of file