class TaskRecurringScheduleService { boolean transactional = false def dateUtilService def taskService /** * Generate all enabled recurring tasks. */ def generateAll() { def taskRecurringScheduleList = TaskRecurringSchedule.findAllByEnabled(true) taskRecurringScheduleList.each() { if ( dateUtilService.tomorrow > it.nextGenerationDate) { def p = [:] // Build the required params. p.targetStartDate = it.nextTargetStartDate p.targetCompletionDate = it.nextTargetCompletionDate if(it.task.taskProcedure) p.taskProcedure = it.task.taskProcedure if(it.task.assignedGroups) p.assignedGroups = new ArrayList(it.task.assignedGroups) if(it.task.assignedPersons) p.assignedPersons = new ArrayList(it.task.assignedPersons) def result = taskService.createSubTask(it.task, p) if( !result.error ) { it.lastGeneratedSubTask = result.taskInstance it.subTasksGenerated++ it.setNextTargetStartDate() it.setNextGenerationDate() it.setNextTargetCompletionDate() } else { log.error "Sub task generation for recurring schedule ${it.id} failed." log.error result.taskInstance.errors } } } } /** * Creates a new recurring schedule for a task with the given params. * @param params The params to use when creating the new recurring schedule. * @returns A map containing result.error=true (if any error) and result.taskRecurringScheduleInstance and result.taskId. */ def create(params) { TaskRecurringSchedule.withTransaction { status -> def result = [:] def fail = { Object[] args -> status.setRollbackOnly() if(args.size() == 2) result.taskRecurringScheduleInstance.errors.rejectValue(args[0], args[1]) result.error = true return result } result.taskRecurringScheduleInstance = new TaskRecurringSchedule(params) result.taskId = result.taskRecurringScheduleInstance.task.id if(!result.taskRecurringScheduleInstance.validate()) return fail() def taskInstance = Task.lock(result.taskId) if(!taskInstance) return fail('task', "task.notFound") if(taskInstance.taskRecurringSchedule) return fail('task', "tast.taskRecurringSchedule.alreadyExists") if(taskInstance.taskStatus.id == 3) return fail('task', "task.operationNotPermittedOnCompleteTask") if(taskInstance.trash) return fail('task', "task.operationNotPermittedOnTaskInTrash") if(result.taskRecurringScheduleInstance.nextTargetStartDate < dateUtilService.today) return fail("nextTargetStartDate", "taskRecurringSchedule.nextTargetStartDate.mayNotBePast") taskInstance.taskRecurringSchedule = result.taskRecurringScheduleInstance if(!result.taskRecurringScheduleInstance.save() || !taskInstance.save()) return fail() // If we get here all went well. return result } //end withTransaction } // end create() /** * Updates an existing recurring schedule. * @param params The params to update for recurring schedule with id of params.id. * @returns A map containing result.error=true (if any error) and result.taskRecurringScheduleInstance (if available). */ def update(params) { TaskRecurringSchedule.withTransaction { status -> def result = [:] def fail = { Object[] args -> status.setRollbackOnly() if(args.size() == 2) result.taskRecurringScheduleInstance.errors.rejectValue(args[0], args[1]) result.error = true return result } result.taskRecurringScheduleInstance = TaskRecurringSchedule.get(params.id) if(!result.taskRecurringScheduleInstance) return fail('id', "taskRecurringSchedule.notFound") // Optimistic locking check. if(params.version) { def version = params.version.toLong() if(result.taskRecurringScheduleInstance.version > version) return fail("version", "default.optimistic.locking.failure") } result.taskRecurringScheduleInstance.properties = params if(result.taskRecurringScheduleInstance.nextTargetStartDate < dateUtilService.today) return fail("nextTargetStartDate", "taskRecurringSchedule.nextTargetStartDate.mayNotBePast") result.taskRecurringScheduleInstance.setNextGenerationDate() result.taskRecurringScheduleInstance.setNextTargetCompletionDate() if(result.taskRecurringScheduleInstance.hasErrors() || !result.taskRecurringScheduleInstance.save()) return fail() // If we get here all went well. return result } //end withTransaction } // end update() } // end of class