class InventoryMovementService {

    boolean transactional = false

    def personService

    def reverseMove(params) {
        InventoryMovement.withTransaction { status ->
            def result = [:]
            result.inventoryMovementInstance = InventoryMovement.lock(params.id)
            if(result.inventoryMovementInstance) {

                // Used type must have a task that is not complete or in the trash
                if(result.inventoryMovementInstance.inventoryMovementType.id == 1)  {

                    // Unlike move, if the task does not exist at all then deletion is still allowed.
                    if(result.inventoryMovementInstance.task?.trash) {
                        status.setRollbackOnly()
                        result.inventoryMovementInstance.errors.rejectValue("task", "task.operationNotPermittedOnTaskInTrash")
                        result.error = true
                        return result
                    }

                    if(result.inventoryMovementInstance.task?.taskStatus?.id == 3) {
                        status.setRollbackOnly()
                        result.inventoryMovementInstance.errors.rejectValue('task', "task.operationNotPermittedOnCompleteTask")
                        result.error = true
                        return result
                    }
                }

                def inventoryItem = InventoryItem.lock(result.inventoryMovementInstance.inventoryItem.id)
                result.taskId = result.inventoryMovementInstance.task?.id

                if(!inventoryItem) {
                        status.setRollbackOnly()
                        result.inventoryMovementInstance.errors.rejectValue('inventoryItem', "inventoryMovement.inventoryItem.notFound")
                        result.error = true
                        return result
                }

                if(result.inventoryMovementInstance.task.taskStatus.id == 3) {
                    status.setRollbackOnly()
                    result.inventoryMovementInstance.errors.rejectValue('task', "task.operationNotPermittedOnCompleteTask")
                    result.error = true
                    return result
                }

                // Reverse the movement of inventory.
                if(!result.inventoryMovementInstance.inventoryMovementType.incrementsInventory) {
                    inventoryItem.unitsInStock += result.inventoryMovementInstance.quantity
                }
                else {
                    if(inventoryItem.unitsInStock >= result.inventoryMovementInstance.quantity) {
                        inventoryItem.unitsInStock -= result.inventoryMovementInstance.quantity
                    }
                    else {
                        status.setRollbackOnly()
                        result.inventoryMovementInstance.errors.rejectValue('quantity', "inventoryMovement.quantity.insufficientItemsInStock")
                        result.error = true
                        return result
                    }
                }

                if(inventoryItem.save() ) {
                    // All went well if we get to this point.
                    result.inventoryMovementInstance.delete()
                    return result
                }
                else {
                    status.setRollbackOnly()
                    result.error = true
                    return result
                }

            }
            else {
                result.error = true
                return result
            }

        } // end withTransaction
    } //end reverseMove()

    def move(params) {
        InventoryMovement.withTransaction { status ->
            def result = [:]
            result.inventoryMovementInstance = new InventoryMovement(params)

            result.inventoryMovementInstance.person = personService.currentUser

            // Used type must have a task that is not complete or in the trash
            if(result.inventoryMovementInstance.inventoryMovementType.id == 1)  {

                if(!result.inventoryMovementInstance.task) {
                    status.setRollbackOnly()
                    result.inventoryMovementInstance.errors.rejectValue('task', "task.notFound")
                    result.error = true
                    return result
                }

                if(result.inventoryMovementInstance.task.trash) {
                    status.setRollbackOnly()
                    result.inventoryMovementInstance.errors.rejectValue("task", "task.operationNotPermittedOnTaskInTrash")
                    result.error = true
                    return result
                }

                if(result.inventoryMovementInstance.task.taskStatus.id == 3) {
                    status.setRollbackOnly()
                    result.inventoryMovementInstance.errors.rejectValue('task', "task.operationNotPermittedOnCompleteTask")
                    result.error = true
                    return result
                }
            }

            if(result.inventoryMovementInstance.validate()) {
                def inventoryItem = InventoryItem.lock(result.inventoryMovementInstance.inventoryItem.id)
                result.taskId = result.inventoryMovementInstance.task?.id

                if(!inventoryItem) {
                    status.setRollbackOnly()
                    result.inventoryMovementInstance.errors.rejectValue('inventoryItem', "inventoryMovement.inventoryItem.notFound")
                    result.error = true
                    return result
                }

                // Perform the movement of inventory.
                if(result.inventoryMovementInstance.inventoryMovementType.incrementsInventory) {
                    inventoryItem.unitsInStock += result.inventoryMovementInstance.quantity
                }
                else {
                    if(inventoryItem.unitsInStock >= result.inventoryMovementInstance.quantity) {
                        inventoryItem.unitsInStock -= result.inventoryMovementInstance.quantity
                    }
                    else {
                        status.setRollbackOnly()
                        result.inventoryMovementInstance.errors.rejectValue('quantity', "inventoryMovement.quantity.insufficientItemsInStock")
                        result.error = true
                        return result
                    }
                }

                if(inventoryItem.save() && result.inventoryMovementInstance.save()) {
                    // All went well if we get to this point.
                    return result
                }
                else {
                    status.setRollbackOnly()
                    result.error = true
                    return result
                }

            }
            else {
                result.error = true
                return result
            }

        } // end withTransaction
    } // end move()

} // end class
