@@ -8,10 +8,13 @@ import com.ffii.fpsms.modules.pickOrder.entity.projection.PickOrderInfo | |||
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus | |||
import com.ffii.fpsms.modules.pickOrder.web.models.* | |||
import com.ffii.fpsms.modules.stock.entity.InventoryLotLineRepository | |||
import com.ffii.fpsms.modules.stock.entity.StockOut | |||
import com.ffii.fpsms.modules.stock.entity.StockOutRepository | |||
import com.ffii.fpsms.modules.stock.entity.projection.CurrentInventoryItemInfo | |||
import com.ffii.fpsms.modules.stock.service.InventoryService | |||
import com.ffii.fpsms.modules.stock.service.StockOutLineService | |||
import com.ffii.fpsms.modules.stock.service.SuggestedPickLotService | |||
import com.ffii.fpsms.modules.stock.web.model.StockOutStatus | |||
import com.ffii.fpsms.modules.stock.web.model.SuggestedPickLotForPoRequest | |||
import com.ffii.fpsms.modules.user.entity.UserRepository | |||
import com.ffii.fpsms.modules.user.service.UserService | |||
@@ -36,6 +39,7 @@ open class PickOrderService( | |||
val userService: UserService, | |||
private val inventoryLotLineRepository: InventoryLotLineRepository, | |||
val inventoryService: InventoryService, | |||
private val stockOutRepository: StockOutRepository | |||
) { | |||
open fun localDateTimeParse(dateTime: String?, pattern: String? = "YYYY-MM-DD hh:mm:ss"): LocalDateTime? { | |||
try { | |||
@@ -149,8 +153,8 @@ open class PickOrderService( | |||
+ " i.name as itemName, " | |||
+ " pol.qty as qty, " | |||
+ " max(uc.code) as uom, " | |||
+ " group_concat(w.name) as warehouse, " | |||
+ " group_concat(il.lotNo) as suggestedLotNo " | |||
+ " group_concat(JSON_ARRAY(w.name)) as warehouse, " | |||
+ " group_concat(JSON_ARRAY(il.lotNo)) as suggestedLotNo " | |||
+ " from pick_order po " | |||
+ " left join pick_order_line pol on pol.poId = po.id " | |||
+ " left join items i on i.id = pol.itemId " | |||
@@ -390,7 +394,14 @@ open class PickOrderService( | |||
val suggestions = | |||
suggestedPickLotService.suggestionForPickOrders(SuggestedPickLotForPoRequest(pickOrders = pos)) | |||
val currUser = SecurityUtils.getUser().orElseThrow() | |||
val stockOut = StockOut().apply { | |||
this.type = "job" | |||
this.consoPickOrderCode = request.consoCode | |||
this.status = StockOutStatus.PENDING.status | |||
this.handler = currUser.id | |||
} | |||
stockOutRepository.save(stockOut) | |||
suggestedPickLotService.saveAll(suggestions.suggestedList) | |||
pickOrderRepository.saveAll(pos) | |||
return ResponseEntity("success", HttpStatus.OK) | |||
@@ -17,11 +17,8 @@ open class StockOut: BaseEntity<Long>(){ | |||
@Column(name = "deliveryOrderCode") | |||
open var deliveryOrderCode: String? = null | |||
@Column(name = "pickOrderCode") | |||
open var pickOrderCode: String? = null | |||
@Column(name = "consoCode") | |||
open var consoCode: String? = null | |||
@Column(name = "consoPickOrderCode") | |||
open var consoPickOrderCode: String? = null | |||
@Column(name = "completeDate") | |||
open var completeDate: LocalDateTime? = null | |||
@@ -1,6 +1,7 @@ | |||
package com.ffii.fpsms.modules.stock.entity | |||
import com.ffii.core.support.AbstractRepository | |||
import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo | |||
import com.ffii.fpsms.modules.stock.web.model.StockOutStatus | |||
import org.springframework.stereotype.Repository | |||
@@ -8,4 +9,5 @@ import org.springframework.stereotype.Repository | |||
interface StockOutLIneRepository: AbstractRepository<StockOutLine, Long> { | |||
fun findAllByStockOutIdAndDeletedFalse(stockOutId: Long): List<StockOutLine> | |||
// fun findAllByStockOutIdAndDeletedFalse(stockOutId: Long, status: StockOutStatus): List<StockOutLine> | |||
fun findAllByPickOrderLineIdAndDeletedFalse(pickOrderLineId: Long): List<StockOutLineInfo> | |||
} |
@@ -25,10 +25,9 @@ open class StockOutLine: BaseEntity<Long>() { | |||
@JoinColumn(name = "stockOutId") | |||
open var stockOut: StockOut? = null | |||
@NotNull | |||
@OneToOne | |||
@JoinColumn(name = "inventoryId") | |||
open var inventory: Inventory? = null | |||
@ManyToOne | |||
@JoinColumn(name = "inventoryLotLineId") | |||
open var inventoryLotLine: InventoryLotLine? = null | |||
@NotNull | |||
@Column(name = "status") | |||
@@ -2,7 +2,9 @@ package com.ffii.fpsms.modules.stock.entity | |||
import com.ffii.core.support.AbstractRepository | |||
import org.springframework.stereotype.Repository | |||
import java.util.Optional | |||
@Repository | |||
interface StockOutRepository: AbstractRepository<StockOut, Long> { | |||
fun findByConsoPickOrderCode(consoPickOrderCode: String) : Optional<StockOut> | |||
} |
@@ -0,0 +1,26 @@ | |||
package com.ffii.fpsms.modules.stock.entity.projection | |||
import org.springframework.beans.factory.annotation.Value | |||
import java.math.BigDecimal | |||
import java.time.LocalDateTime | |||
interface StockOutLineInfo { | |||
val id: Long | |||
@get:Value("#{target.item?.id}") | |||
val itemId: Long | |||
@get:Value("#{target.item?.name}") | |||
val itemName: String? | |||
val itemNo: String | |||
val qty: BigDecimal | |||
@get:Value("#{target.stockOut?.id}") | |||
val stockOutId: Long | |||
@get:Value("#{target.pickOrderLine?.id}") | |||
val pickOrderLineId: Long | |||
@get:Value("#{target.inventoryLotLine?.id}") | |||
val inventoryLotLineId: Long? | |||
val status: String | |||
val pickTime: LocalDateTime? | |||
} |
@@ -4,7 +4,9 @@ import com.ffii.core.support.AbstractBaseEntityService | |||
import com.ffii.core.support.JdbcDao | |||
import com.ffii.fpsms.modules.master.entity.ItemsRepository | |||
import com.ffii.fpsms.modules.master.web.models.MessageResponse | |||
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderLineRepository | |||
import com.ffii.fpsms.modules.stock.entity.* | |||
import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo | |||
import com.ffii.fpsms.modules.stock.web.model.SaveStockOutLineRequest | |||
import com.ffii.fpsms.modules.stock.web.model.SaveStockOutRequest | |||
import com.ffii.fpsms.modules.stock.web.model.StockOutLineStatus | |||
@@ -18,102 +20,76 @@ import java.time.LocalDateTime | |||
@Service | |||
open class StockOutLineService( | |||
private val jdbcDao: JdbcDao, | |||
private val pickOrderLineRepository: PickOrderLineRepository, | |||
private val stockOutRepository: StockOutRepository, | |||
private val stockOutLIneRepository: StockOutLIneRepository, | |||
private val stockOutLineRepository: StockOutLIneRepository, | |||
private val itemRepository: ItemsRepository, | |||
private val inventoryRepository: InventoryRepository, | |||
): AbstractBaseEntityService<StockOutLine, Long, StockOutLIneRepository>(jdbcDao, stockOutLIneRepository) { | |||
private val inventoryLotLineRepository: InventoryLotLineRepository | |||
): AbstractBaseEntityService<StockOutLine, Long, StockOutLIneRepository>(jdbcDao, stockOutLineRepository) { | |||
@Throws(IOException::class) | |||
@Transactional | |||
open fun findAllByStockOutId(stockOutId: Long): List<StockOutLine> { | |||
return stockOutLIneRepository.findAllByStockOutIdAndDeletedFalse(stockOutId) | |||
return stockOutLineRepository.findAllByStockOutIdAndDeletedFalse(stockOutId) | |||
} | |||
@Throws(IOException::class) | |||
@Transactional | |||
open fun deleteById(id: Long): String { | |||
val deleteStockOutline = stockOutLIneRepository.findById(id).orElseThrow().apply { | |||
val deleteStockOutline = stockOutLineRepository.findById(id).orElseThrow().apply { | |||
deleted = true | |||
} | |||
val updateItem = stockOutLIneRepository.save(deleteStockOutline) | |||
val updateItem = stockOutLineRepository.save(deleteStockOutline) | |||
val response = "mark deleted item: ${updateItem.id}" | |||
return response | |||
} | |||
@Throws(IOException::class) | |||
@Transactional | |||
open fun deleteByStockOutId(id: Long): String { | |||
val deleteStockOutline = stockOutLIneRepository.findAllByStockOutIdAndDeletedFalse(id).map {sol -> | |||
val deleteStockOutline = stockOutLineRepository.findAllByStockOutIdAndDeletedFalse(id).map {sol -> | |||
sol.apply { | |||
deleted = true | |||
} | |||
} | |||
val updateItemIds = stockOutLIneRepository.saveAllAndFlush(deleteStockOutline).map { it.id } | |||
val updateItemIds = stockOutLineRepository.saveAllAndFlush(deleteStockOutline).map { it.id } | |||
val response = "mark deleted items: $updateItemIds" | |||
return response | |||
} | |||
@Throws(IOException::class) | |||
@Transactional | |||
/// only create?????? | |||
open fun getAllStockOutLineByPickOrderLineId(pickOrderLineId: Long): List<StockOutLineInfo> { | |||
return stockOutLineRepository.findAllByPickOrderLineIdAndDeletedFalse(pickOrderLineId) | |||
} | |||
@Transactional | |||
open fun create(request: SaveStockOutLineRequest): MessageResponse { | |||
val stockOutLine = StockOutLine() | |||
val stockOut = stockOutRepository.findByConsoPickOrderCode(request.consoCode).orElseThrow() | |||
val pickOrderLine = pickOrderLineRepository.findById(request.pickOrderLineId).orElseThrow() | |||
val item = itemRepository.findById(request.itemId).orElseThrow() | |||
stockOutLine.apply { | |||
this.item = item | |||
qty = request.qty | |||
status = StockOutLineStatus.PENDING.status //create the base record = the original total sum of one item | |||
} | |||
val savedStockOutLine = stockOutLIneRepository.saveAndFlush(stockOutLine) | |||
val inventoryLotLine = inventoryLotLineRepository.findById(request.inventoryLotLineId).orElseThrow() | |||
val stockOutLine = StockOutLine() | |||
.apply { | |||
this.item = item | |||
this.qty = request.qty | |||
this.stockOut = stockOut | |||
this.inventoryLotLine | |||
this.pickOrderLine = pickOrderLine | |||
this.status = StockOutLineStatus.PENDING.status | |||
} | |||
val savedStockOutLine = saveAndFlush(stockOutLine) | |||
return MessageResponse( | |||
id = savedStockOutLine.id, | |||
code = item.code, | |||
name = item.name, | |||
name = savedStockOutLine.inventoryLotLine!!.inventoryLot!!.lotNo, | |||
code = savedStockOutLine.stockOut!!.consoPickOrderCode, | |||
type = savedStockOutLine.status, | |||
message = "save success", | |||
errorPosition = null | |||
message = "success", | |||
errorPosition = null, | |||
entity = savedStockOutLine, | |||
) | |||
} | |||
// stock out -> stock out line record : {qty = 100} | |||
// each pick create new stock out line {...sol, status = picked} | |||
// when confirm all picked and complete in web | |||
// update: | |||
// 1.stock out status | |||
// remove: | |||
// 1.stock out line : {qty = 100} | |||
@Throws(IOException::class) | |||
@Transactional | |||
open fun pick(request: SaveStockOutLineRequest): MessageResponse { | |||
val item = itemRepository.findById(request.itemId).orElseThrow() | |||
if (request.inventoryId === null) { | |||
return MessageResponse( | |||
id = request.id, | |||
code = null, | |||
name = item.name, | |||
type = null, | |||
message = "inventory is null or not exist", | |||
errorPosition = "inventoryId" | |||
) | |||
} | |||
val stockOutLine = StockOutLine() | |||
val _stockOut = stockOutRepository.findById(request.stockOutId).orElseThrow() | |||
val _inventory = inventoryRepository.findById(request.inventoryId).orElseThrow() | |||
val picker = request.pickerId | |||
stockOutLine.apply { | |||
this.item = item | |||
qty = request.qty | |||
stockOut = _stockOut | |||
inventory = _inventory | |||
status = "picked" | |||
pickTime = LocalDateTime.now() | |||
pickerId = picker | |||
} | |||
val savedOutLine = stockOutLIneRepository.saveAndFlush(stockOutLine) | |||
return MessageResponse( | |||
id = savedOutLine.id, | |||
code = null, | |||
name = null, | |||
type = savedOutLine.status, | |||
message = "item picked", | |||
errorPosition = null | |||
) | |||
open fun update(request: SaveStockOutLineRequest) { | |||
val stockOutLine = stockOutLineRepository.findById(request.id!!).orElseThrow() | |||
} | |||
} |
@@ -25,35 +25,6 @@ open class StockOutService( | |||
): AbstractBaseEntityService<StockOut, Long, StockOutRepository>(jdbcDao, stockOutRepository) { | |||
@Throws(IOException::class) | |||
@Transactional | |||
// update record data | |||
open fun saveStockOut(request: SaveStockOutRequest): MessageResponse { | |||
val stockOut = if (request.id !== null) stockOutRepository.findById(request.id).orElseThrow() else StockOut() | |||
stockOut.apply { | |||
type = request.type | |||
deliveryOrderCode = request.deliveryOrderCode | |||
pickOrderCode = request.pickOrderCode | |||
consoCode = request.consoCode | |||
completeDate = request.completeDate | |||
handler = request.handler | |||
targetOutletId = request.targetOutletId | |||
remarks = request.remarks | |||
} | |||
val savedStockOut = stockOutRepository.saveAndFlush(stockOut) | |||
// only create stock out line, no update | |||
for (outLine in request.stockOutLine) { | |||
stockOutLineService.create(outLine) | |||
} | |||
return MessageResponse( | |||
id = savedStockOut.id, | |||
code = savedStockOut.pickOrderCode ?: savedStockOut.deliveryOrderCode , | |||
name = savedStockOut.consoCode, | |||
type = savedStockOut.type, | |||
message = "save success", | |||
errorPosition = null | |||
) | |||
} | |||
@Throws(IOException::class) | |||
@Transactional | |||
open fun complete(request: SaveStockOutRequest): MessageResponse { | |||
if (request.id === null) { | |||
return MessageResponse( | |||
@@ -80,8 +51,8 @@ open class StockOutService( | |||
if (!isBalanced) { | |||
return MessageResponse( | |||
id = request.id, | |||
code = stockOut.consoCode, | |||
name = stockOut.pickOrderCode ?: stockOut.deliveryOrderCode, | |||
code = "stockOut.consoCode", | |||
name = "stockOut.pickOrderCode ?: stockOut.deliveryOrderCode", | |||
type = stockOut.type, | |||
message = "there are items not picked", | |||
errorPosition = null | |||
@@ -101,7 +72,7 @@ open class StockOutService( | |||
val ledgers = pickLines.map {stockOutLine -> | |||
StockLedger().apply { | |||
this.stockOutLine = stockOutLine | |||
this.inventory = stockOutLine.inventory | |||
// this.inventory = stockOutLine.inventory | |||
outQty = stockOutLine.qty | |||
} | |||
} | |||
@@ -115,8 +86,8 @@ open class StockOutService( | |||
val savedStockOut = stockOutRepository.saveAndFlush(stockOut) | |||
return MessageResponse( | |||
id = savedStockOut.id, | |||
code = savedStockOut.consoCode, | |||
name = savedStockOut.pickOrderCode ?: savedStockOut.deliveryOrderCode, | |||
code = "savedStockOut.consoCode", | |||
name = "savedStockOut.pickOrderCode ?: savedStockOut.deliveryOrderCode", | |||
type = savedStockOut.type, | |||
message = "stock out completed", | |||
errorPosition = null | |||
@@ -37,6 +37,9 @@ class InventoryLotLineController ( | |||
val zero = BigDecimal.ZERO | |||
return LotLineInfo( | |||
inventoryLotLineId = inventoryLotLine.id!!, | |||
itemId = inventoryLotLine.inventoryLot!!.item!!.id!!, | |||
itemNo = inventoryLotLine.inventoryLot!!.item!!.code!!, | |||
itemName = inventoryLotLine.inventoryLot!!.item!!.name!!, | |||
lotNo = stockInLine.lotNo!!, | |||
remainingQty = (inventoryLotLine.inQty ?: zero) | |||
.minus(inventoryLotLine.outQty ?: zero) | |||
@@ -0,0 +1,25 @@ | |||
package com.ffii.fpsms.modules.stock.web | |||
import com.ffii.fpsms.modules.purchaseOrder.entity.PurchaseOrderLine | |||
import com.ffii.fpsms.modules.stock.entity.StockOutLine | |||
import com.ffii.fpsms.modules.stock.entity.projection.StockOutLineInfo | |||
import com.ffii.fpsms.modules.stock.service.StockInLineService | |||
import com.ffii.fpsms.modules.stock.service.StockOutLineService | |||
import jakarta.validation.Valid | |||
import org.springframework.web.bind.annotation.GetMapping | |||
import org.springframework.web.bind.annotation.PathVariable | |||
import org.springframework.web.bind.annotation.PostMapping | |||
import org.springframework.web.bind.annotation.RequestMapping | |||
import org.springframework.web.bind.annotation.RestController | |||
@RestController | |||
@RequestMapping("/stockOutLine") | |||
class StockOutLineController( | |||
private val stockOutLineService: StockOutLineService | |||
) { | |||
@GetMapping("/getByPickOrderLineId/{pickOrderLineId}") | |||
fun getByPurchaseOrderLineId(@Valid @PathVariable pickOrderLineId: Long): List<StockOutLineInfo> { | |||
return stockOutLineService.getAllStockOutLineByPickOrderLineId(pickOrderLineId) | |||
} | |||
} |
@@ -4,6 +4,9 @@ import java.math.BigDecimal | |||
data class LotLineInfo( | |||
val inventoryLotLineId: Long, | |||
val itemId: Long, | |||
val itemNo: String, | |||
val itemName: String, | |||
val lotNo: String, | |||
val remainingQty: BigDecimal, | |||
val uom: String | |||
@@ -30,10 +30,11 @@ data class SaveStockOutRequest( | |||
data class SaveStockOutLineRequest( | |||
val id: Long?, | |||
val consoCode: String, | |||
val itemId: Long, | |||
val qty: Double, | |||
val stockOutId: Long, | |||
val inventoryId: Long?, | |||
val pickOrderLineId: Long, | |||
val inventoryLotLineId: Long, | |||
val status: StockOutLineStatus?, | |||
val pickTime: LocalDateTime?, | |||
val pickerId: Long? | |||
@@ -77,6 +77,15 @@ public class UserService extends AbstractBaseEntityService<User, Long, UserRepos | |||
}); | |||
} | |||
public User getUserById(Long id) { | |||
User user = userRepository.findById(id).orElseThrow(); | |||
Set<GrantedAuthority> auths = new LinkedHashSet<GrantedAuthority>(); | |||
auths.add(new SimpleGrantedAuthority("ROLE_USER")); | |||
jdbcDao.queryForList(USER_AUTH_SQL + UNION_SQL + GROUP_AUTH_SQL, Map.of("userId", user.getId())) | |||
.forEach(item -> auths.add(new SimpleGrantedAuthority((String) item.get("authority")))); | |||
user.setAuthorities(auths); | |||
return user; | |||
} | |||
public Optional<User> findByUsername(String username) { | |||
return userRepository.findByUsernameAndDeletedFalse(username); | |||
} | |||
@@ -98,7 +98,11 @@ public class UserController{ | |||
logger.info(test); | |||
return test; | |||
} | |||
@GetMapping("/user-info/{id}") | |||
// @PreAuthorize("hasAuthority('VIEW_USER')") | |||
public ResponseEntity<?> getUserById(@PathVariable Long id) throws NotFoundException { | |||
return ResponseEntity.ok(userService.getUserById(id)); | |||
} | |||
// @Operation(summary = "delete user", responses = { @ApiResponse(responseCode = "204"), | |||
// @ApiResponse(responseCode = "404", content = @Content) }) | |||
@DeleteMapping("/{id}") | |||
@@ -123,6 +127,7 @@ public class UserController{ | |||
// @PreAuthorize("hasAuthority('MAINTAIN_USER')") | |||
public ResponseEntity<?> createPublicUserRecord(@RequestBody NewPublicUserReq req) throws UnsupportedEncodingException { | |||
logger.info("Create user request:"); | |||
req.setPassword("mms1234"); // default for now | |||
return ResponseEntity.ok(new IdRes(userService.newPublicUserRecord(req).getId())) ; | |||
} | |||
@@ -197,6 +202,7 @@ public class UserController{ | |||
return ResponseEntity.ok(password); | |||
} | |||
// @Operation(summary = "get password rules") | |||
@GetMapping("/password-rule") | |||
public PasswordRule passwordRlue() { | |||
@@ -0,0 +1,7 @@ | |||
-- liquibase formatted sql | |||
-- changeset derek:update_stockoutline_lot_line_id | |||
ALTER TABLE `stock_out_line` | |||
CHANGE COLUMN `inventoryId` `inventoryLotLineId` INT(11) NULL, | |||
ADD CONSTRAINT FK_STOCK_OUT_LINE_ON_LOT_LINE_ID FOREIGN KEY (inventoryLotLineId) REFERENCES inventory_lot_line (id) | |||
; |
@@ -0,0 +1,7 @@ | |||
-- liquibase formatted sql | |||
-- changeset derek:remove_consoCode_change_pickOrderCode | |||
ALTER TABLE `stock_out` | |||
DROP COLUMN `consoCode`, | |||
CHANGE COLUMN `pickOrderCode` `consoPickOrderCode` VARCHAR(255) NULL | |||
; |