Changeset 418


Ignore:
Timestamp:
Feb 28, 2010, 7:13:47 PM (14 years ago)
Author:
gav
Message:

Add attentionFlag to Task domain along with views and logic to suite.
Add entry type 'cause', refactor as required.
Refactor task types.
Move createBreakin to createImmediateCallout.

Location:
trunk
Files:
1 added
1 deleted
10 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/conf/Config.groovy

    r414 r418  
    104104            warn "grails.app.controller"
    105105            info "grails.app.service.AssetCsvService"
     106            info "grails.app.service.InventoryCsvService"
    106107            break
    107108    }
     
    146147            [order:10, controller:'taskDetailed', title:'Search', action:'search', isVisible: { true }],
    147148            [order:11, controller:'taskDetailed', title:'Calendar', action:'searchCalendar', isVisible: { true }],
    148             [order:20, controller:'taskDetailed', title:'Create', action:'create', isVisible: { true }],
    149             [order:30, controller:'taskDetailed', title:'Breakin', action:'createBreakin', isVisible: { true }],
     149            [order:20, controller:'taskDetailed', title:'+Scheduled', action:'create', isVisible: { true }],
     150            [order:30, controller:'taskDetailed', title:'+Callout', action:'createImmediateCallout', isVisible: { true }],
    150151            [order:90, controller:'taskDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
    151152            [order:91, controller:'taskDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
  • trunk/grails-app/controllers/TaskDetailedController.groovy

    r395 r418  
    1414
    1515    // these actions only accept POST requests
    16     static allowedMethods = [save:'POST', update:'POST', restore:'POST', trash:'POST', approve:'POST', renegeApproval:'POST', complete:'POST', reopen:'POST']
     16    static allowedMethods = [save:'POST',update:'POST',restore:'POST', trash:'POST',
     17                                                approve:'POST', renegeApproval:'POST', complete:'POST',
     18                                                reopen:'POST', setAttentionFlag:'POST', clearAttentionFlag:'POST']
    1719
    1820    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    1921    def index = { redirect(action: 'search', params: params) }
    20 
    21     @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    22     def list = {
    23         params.max = Math.min( params.max ? params.max.toInteger() : 10,  100 )
    24         [ taskInstanceList: Task.list( params ), taskInstanceTotal: Task.count() ]
    25     }
    2622
    2723    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
     
    115111        filterParams.max = params.max
    116112        filterParams.offset = params.offset?.toInteger() ?: 0
    117         filterParams.sort = params.sort ?: "id"
     113        filterParams.sort = params.sort ?: "attentionFlag"
    118114        filterParams.order = params.order ?: "desc"
    119115
     
    253249            params.sort = "id"
    254250
    255             def entryWorkDoneList = Entry.withCriteria {
    256                                                                 eq("entryType", EntryType.get(2))
    257                                                                 eq("task", taskInstance)
    258                                                         }
    259 
    260251            def entryFaultList = Entry.withCriteria {
    261252                                                                eq("entryType", EntryType.get(1))
     
    263254                                                        }
    264255
     256            def entryCauseList = Entry.withCriteria {
     257                                                                eq("entryType", EntryType.get(2))
     258                                                                eq("task", taskInstance)
     259                                                        }
     260
     261            def entryWorkDoneList = Entry.withCriteria {
     262                                                                eq("entryType", EntryType.get(3))
     263                                                                eq("task", taskInstance)
     264                                                        }
     265
    265266            def subTaskInstanceList = Task.findAllByParentTaskAndTrash(taskInstance, false, params)
    266267            def subTaskInstanceTotal = Task.countByParentTaskAndTrash(taskInstance, false)
     
    290291
    291292            return [ taskInstance: taskInstance,
     293                            entryFaultList: entryFaultList,
     294                            entryCauseList: entryCauseList,
    292295                            entryWorkDoneList: entryWorkDoneList,
    293                             entryFaultList: entryFaultList,
    294296                            taskProcedureInstance: taskProcedureInstance,
    295297                            taskProcedureExits: taskProcedureExits,
     
    308310    }
    309311
     312    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    310313    def restore = {
    311314
    312         if(!Task.exists(params.id)) {
    313             flash.message = "Task not found with id ${params.id}"
    314             redirect(action: 'search')
    315         }
    316 
    317315        def result = taskService.restore(params)
    318316
    319317        if(!result.error) {
    320318                flash.message = "Task ${params.id} has been restored."
    321                 redirect(action: 'show', id: result.taskInstance.id)
    322         }
    323         else {
    324             if(result.taskInstance) {
    325                 render(view:'edit',model:[taskInstance:result.taskInstance])
    326             }
    327             else {
    328                 flash.message = "Task could not be updated."
    329                 redirect(action: 'search')
    330             }
    331         }
    332 
    333     }
    334 
     319                redirect(action: show, id: params.id)
     320                return
     321        }
     322
     323        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
     324
     325        if(result.taskInstance)
     326            redirect(action: show, id: params.id)
     327        else
     328            redirect(action: 'search')
     329
     330    }
     331
     332    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    335333    def trash = {
    336 
    337         if(!Task.exists(params.id)) {
    338             flash.message = "Task not found with id ${params.id}."
    339             redirect(action: 'search')
    340         }
    341334
    342335        def result = taskService.trash(params)
     
    345338                flash.message = "Task ${params.id} has been moved to trash."
    346339                redirect(action: 'search')
    347         }
    348         else {
    349             if(result.taskInstance) {
    350                 render(view:'edit',model:[taskInstance:result.taskInstance])
    351             }
    352             else {
    353                 flash.message = "Task could not be updated."
    354                 redirect(action: 'search')
    355             }
    356         }
    357 
    358     }
    359 
     340                return
     341        }
     342
     343        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
     344
     345        if(result.taskInstance)
     346            redirect(action: show, id: params.id)
     347        else
     348            redirect(action: 'search')
     349
     350    }
     351
     352    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager'])
    360353    def approve = {
    361354
    362         if(!Task.exists(params.id)) {
    363             flash.message = "Task not found with id ${params.id}."
    364             redirect(action: 'search')
    365         }
    366 
    367355        def result = taskService.approve(params)
    368356
    369357        if(!result.error) {
    370358                flash.message = "Task ${params.id} has been approved."
    371                 redirect(action: 'show', id: result.taskInstance.id)
    372         }
    373         else {
    374             if(result.taskInstance) {
    375                 render(view:'edit',model:[taskInstance:result.taskInstance])
    376             }
    377             else {
    378                 flash.message = "Task could not be updated."
    379                 redirect(action: 'search')
    380             }
    381         }
    382 
    383     }
    384 
     359                redirect(action: show, id: params.id)
     360                return
     361        }
     362
     363        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
     364
     365        if(result.taskInstance)
     366            redirect(action: show, id: params.id)
     367        else
     368            redirect(action: 'search')
     369
     370    }
     371
     372    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    385373    def renegeApproval = {
    386374
    387         if(!Task.exists(params.id)) {
    388             flash.message = "Task not found with id ${params.id}."
    389             redirect(action: 'search')
    390         }
    391 
    392375        def result = taskService.renegeApproval(params)
    393376
    394377        if(!result.error) {
    395378                flash.message = "Task ${params.id} has had approval removed."
    396                 redirect(action: 'show', id: result.taskInstance.id)
    397         }
    398         else {
    399             if(result.taskInstance) {
    400                 render(view:'edit',model:[taskInstance:result.taskInstance])
    401             }
    402             else {
    403                 flash.message = "Task could not be updated."
    404                 redirect(action: 'search')
    405             }
    406         }
     379                redirect(action: show, id: params.id)
     380                return
     381        }
     382
     383        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
     384
     385        if(result.taskInstance)
     386            redirect(action: show, id: params.id)
     387        else
     388            redirect(action: 'search')
    407389
    408390    }
     
    411393    def complete = {
    412394
    413         if(!Task.exists(params.id)) {
    414             flash.message = "Task not found with id ${params.id}."
    415             redirect(action: 'search')
    416         }
    417 
    418395        def result = taskService.complete(params)
    419396
    420397        if(!result.error) {
    421398                flash.message = "Task ${params.id} has been completed."
    422                 redirect(action: 'show', id: result.taskInstance.id)
    423         }
    424         else {
    425             if(result.taskInstance) {
    426                 render(view:'edit',model:[taskInstance:result.taskInstance])
    427             }
    428             else {
    429                 flash.message = "Task could not be updated."
    430                 redirect(action: 'search')
    431             }
    432         }
     399                redirect(action: show, id: params.id)
     400                return
     401        }
     402
     403        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
     404
     405        if(result.taskInstance)
     406            redirect(action: show, id: params.id)
     407        else
     408            redirect(action: 'search')
     409
     410    }
     411
     412    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
     413    def setAttentionFlag = {
     414
     415        def result = taskService.setAttentionFlag(params)
     416
     417        if(!result.error) {
     418                flash.message = "Task ${params.id} has been flagged for attention."
     419                redirect(action: show, id: params.id)
     420                return
     421        }
     422
     423        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
     424
     425        if(result.taskInstance)
     426            redirect(action: show, id: params.id)
     427        else
     428            redirect(action: 'search')
     429
     430    }
     431
     432    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
     433    def clearAttentionFlag = {
     434
     435        def result = taskService.clearAttentionFlag(params)
     436
     437        if(!result.error) {
     438                flash.message = "Task ${params.id} attention flag cleared."
     439                redirect(action: show, id: params.id)
     440                return
     441        }
     442
     443        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
     444
     445        if(result.taskInstance)
     446            redirect(action: show, id: params.id)
     447        else
     448            redirect(action: 'search')
    433449
    434450    }
     
    437453    def reopen = {
    438454
    439         if(!Task.exists(params.id)) {
    440             flash.message = "Task not found with id ${params.id}."
    441             redirect(action: 'search')
    442         }
    443 
    444455        def result = taskService.reopen(params)
    445456
    446457        if(!result.error) {
    447458                flash.message = "Task ${params.id} has been reopened."
    448                 redirect(action: 'show', id: result.taskInstance.id)
    449         }
    450         else {
    451             if(result.taskInstance) {
    452                 render(view:'edit',model:[taskInstance:result.taskInstance])
    453             }
    454             else {
    455                 flash.message = "Task could not be updated."
    456                 redirect(action: 'search')
    457             }
    458         }
     459                redirect(action: show, id: params.id)
     460                return
     461        }
     462
     463        flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
     464
     465        if(result.taskInstance)
     466            redirect(action: show, id: params.id)
     467        else
     468            redirect(action: 'search')
    459469
    460470    }
     
    488498    def update = {
    489499
    490         if(!Task.exists(params.id)) {
    491             flash.message = "Task not found with id ${params.id}"
    492             redirect(action: 'search')
    493         }
    494 
    495500        def result = taskService.update(params)
    496501
    497502        if(!result.error) {
    498503                flash.message = "Task ${params.id} updated"
    499                 redirect(action: 'show', id: result.taskInstance.id)
    500         }
    501         else {
    502             render(view:'edit',model:[taskInstance:result.taskInstance.attach()])
    503         }
     504                redirect(action: show, id: params.id)
     505                return
     506        }
     507
     508        if(result.error.code == "task.modifications.failedToSave")
     509            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
     510
     511        render(view:'edit',model:[taskInstance:result.taskInstance.attach()])
    504512
    505513    }
     
    526534            flash.message = "Task ${result.taskInstance.id} created."
    527535            redirect(action: 'show', id: result.taskInstance.id)
    528         }
    529         else {
    530             if(result.taskInstance) {
    531                 render(view:'create', model:[taskInstance:result.taskInstance])
    532             }
    533             else {
    534                 flash.message = "Could not create task."
    535                 redirect(action: 'search')
    536             }
    537 
    538         }
     536            return
     537        }
     538
     539        if(result.error.code == "task.modifications.failedToSave")
     540            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
     541
     542        render(view:'create', model:[taskInstance:result.taskInstance])
    539543    }
    540544
     
    571575            else {
    572576                if(result.taskInstance.errors.hasFieldErrors("parentTask")) {
    573                     flash.message = g.message(code:"task.operationNotPermittedOnTaskInTrash")
     577                    flash.errorMessage = g.message(code:"task.operationNotPermittedOnTaskInTrash")
    574578                    redirect(action: 'show', id:  parentTaskInstance.id)
    575579                }
     
    587591
    588592    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    589     def createBreakin = {
     593    def createImmediateCallout = {
    590594        def taskInstance = new Task()
    591595
    592596        def entryFaultInstance = new Entry(entryType: EntryType.get(1))  // Fault.
    593         def entryWorkDoneInstance = new Entry(entryType: EntryType.get(2))  // Work Done.
     597        def entryCauseInstance = new Entry(entryType: EntryType.get(2))  // Cause.
     598        def entryWorkDoneInstance = new Entry(entryType: EntryType.get(3))  // Work Done.
    594599
    595600        return ['taskInstance': taskInstance,
    596601                        'entryFaultInstance': entryFaultInstance,
     602                        'entryCauseInstance': entryCauseInstance,
    597603                        'entryWorkDoneInstance': entryWorkDoneInstance]
    598604    }
    599605
    600606    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
    601     def saveBreakin = {
    602         def result = taskService.saveBreakin(params)
     607    def saveImmediateCallout = {
     608        def result = taskService.saveImmediateCallout(params)
    603609
    604610        if(!result.error) {
     
    611617            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
    612618
    613         render(view:'createBreakin',
     619        render(view:'createImmediateCallout',
    614620                    model: ['taskInstance': result.taskInstance,
    615621                                'entryFaultInstance': result.entryFaultInstance,
     622                                'entryCauseInstance': result.entryCauseInstance,
    616623                                'entryWorkDoneInstance': result.entryWorkDoneInstance])
    617624
  • trunk/grails-app/domain/Task.groovy

    r252 r418  
    1919    boolean approved = false
    2020    boolean trash = false
     21    boolean attentionFlag = false
    2122
    22     static hasMany = [entries: Entry, 
     23    static hasMany = [entries: Entry,
    2324                        taskModifications: TaskModification,
    2425                        assignedGroups: AssignedGroup,
  • trunk/grails-app/i18n/messages.properties

    r414 r418  
    5959entry.comment.fault.help=Describe the fault and what is happening, NOT what needs doing! \
    6060<br /><br />From an operation perspective, NOT a technical perspective.
     61entry.comment.cause=Cause
     62entry.comment.cause.help=The root cause of the fault. Professional opinion on any faults. \
     63Include condition and contributing factors.
    6164entry.comment.work.done=Work Done
    62 entry.comment.work.done.help=Describe the work that was done. \
    63 Include the root cause if known or professional opinion on any faults. \
    64 Include condition and contributing factors.
     65entry.comment.work.done.help=Describe the work that was done.
    6566
    6667assignedGroup.estimatedDuration=Estimated Duration
  • trunk/grails-app/services/CreateBulkDataService.groovy

    r399 r418  
    145145        def taskGroup1 = TaskGroup.get(1)
    146146        def taskPriority2 = TaskPriority.get(2)
    147         def taskType1 = TaskType.get(1)
     147        def taskType3 = TaskType.get(3)
    148148        def leadPerson2 = Person.get(2)
    149149
     
    168168            p = [taskGroup: taskGroup1,
    169169                    taskPriority: taskPriority2,
    170                     taskType: taskType1,
     170                    taskType: taskType3,
    171171                    leadPerson: leadPerson2,
    172172                    description: btDescription,
  • trunk/grails-app/services/CreateDataService.groovy

    r402 r418  
    685685        def taskTypeInstance
    686686
    687         taskTypeInstance = new TaskType(name:"Unscheduled Breakin") // #1
     687        taskTypeInstance = new TaskType(name:"Immediate Callout") // #1
    688688        saveAndTest(taskTypeInstance)
    689689
    690         taskTypeInstance = new TaskType(name:"Preventative Maintenance") // #2
     690        taskTypeInstance = new TaskType(name:"Unscheduled Breakin") // #2
    691691        saveAndTest(taskTypeInstance)
    692692
    693         taskTypeInstance = new TaskType(name:"Project") // #3
     693        taskTypeInstance = new TaskType(name:"Scheduled") // #3
    694694        saveAndTest(taskTypeInstance)
    695695
    696         taskTypeInstance = new TaskType(name:"Turnaround") // #4
     696        taskTypeInstance = new TaskType(name:"Preventative Maintenance") // #4
    697697        saveAndTest(taskTypeInstance)
    698698
    699         taskTypeInstance = new TaskType(name:"Production Run") // #5
     699        taskTypeInstance = new TaskType(name:"Predictive Maintenance") // #5
     700        saveAndTest(taskTypeInstance)
     701
     702        taskTypeInstance = new TaskType(name:"Project") // #6
    700703        saveAndTest(taskTypeInstance)
    701704    }
     
    716719        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Assigned Groups)").save()  // #10
    717720        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Assigned Persons)").save()  // #11
     721        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Flagged for attention)").save()  // #12
     722        taskModificationTypeInstance = new TaskModificationType(name:"Modified (Attention flag cleared)").save()  // #13
    718723    }
    719724
     
    728733                taskType:TaskType.get(1),
    729734                leadPerson:Person.get(2),
    730                 description:"Check specific level sensor",
     735                description:"Level sensor not working",
    731736                comment:"Has been noted as problematic, try recalibrating.",
    732737                targetStartDate: dateUtilService.today]
     
    737742        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
    738743                taskPriority:TaskPriority.get(2),
    739                 taskType:TaskType.get(1),
     744                taskType:TaskType.get(3),
    740745                leadPerson:Person.get(5),
    741746                description:"Some follow-up work",
     
    749754        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
    750755                taskPriority:TaskPriority.get(2),
    751                 taskType:TaskType.get(1),
     756                taskType:TaskType.get(3),
    752757                leadPerson:Person.get(5),
    753                 description:"A Sub Task can be created from the Sub Task's tab.",
     758                description:"A Sub Task can be created from the 'Sub Task' tab.",
    754759                comment:"Some help required",
    755760                targetStartDate: dateUtilService.yesterday,
     
    761766        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
    762767                 taskPriority:TaskPriority.get(2),
    763                  taskType:TaskType.get(1),
     768                 taskType:TaskType.get(2),
    764769                 leadPerson:Person.get(4),
    765                  description:"Replace sensor at next opportunity.",
    766                  comment:"Nothing else has worked.",
     770                 description:"Please replace sensor at next available opportunity.",
     771                 comment:"Nothing else has worked. So we now require the part to be replaced.",
    767772                targetStartDate: dateUtilService.oneWeekFromNow,
    768773                parentTask: Task.get(1)]
     
    773778        p = [taskGroup:TaskGroup.findByName("Production Activites"),
    774779                 taskPriority:TaskPriority.get(2),
    775                  taskType:TaskType.get(5),
     780                 taskType:TaskType.get(3),
    776781                 leadPerson:Person.get(6),
    777                  description:"Production Report",
    778                  comment:"Production report for specific production run or shift",
     782                 description:"Production Task",
     783                 comment:"Production task for specific production run or shift",
    779784                targetStartDate: dateUtilService.today - 6]
    780785
     
    783788        //Task #6
    784789        p = [taskGroup:TaskGroup.findByName("Engineering Activites"),
    785                  taskPriority:TaskPriority.get(1),
    786                  taskType:TaskType.get(2),
     790                 taskPriority:TaskPriority.get(4),
     791                 taskType:TaskType.get(3),
    787792                 leadPerson:Person.get(4),
    788                  description:"This is a recurring task",
     793                 description:"This is a recurring preventative maintenance task.",
    789794                 comment:"If there is a parent task specified then this is a generated sub task, if there is a recurring schedule specified then this is a parent task.",
    790795                targetStartDate: dateUtilService.today]
     
    801806        saveAndTest(entryTypeInstance)
    802807
    803         entryTypeInstance = new EntryType(name:"Work Done") // #2
     808        entryTypeInstance = new EntryType(name:"Cause") // #2
    804809        saveAndTest(entryTypeInstance)
    805810
    806         entryTypeInstance = new EntryType(name:"Production Note") // #3
     811        entryTypeInstance = new EntryType(name:"Work Done") // #3
    807812        saveAndTest(entryTypeInstance)
    808813
    809         entryTypeInstance = new EntryType(name:"Work Request") // #4
     814        entryTypeInstance = new EntryType(name:"Production Note") // #4
     815        saveAndTest(entryTypeInstance)
     816
     817        entryTypeInstance = new EntryType(name:"Work Request") // #5
    810818        saveAndTest(entryTypeInstance)
    811819    }
     
    826834        //Entry #2
    827835        p = [task: Task.get(1),
    828                 entryType: EntryType.get(2),
     836                entryType: EntryType.get(3),
    829837                comment: "Cleaned sensor, see how it goes.",
    830838                durationMinute: 30]
     
    834842        //Entry #3
    835843        p = [task: Task.get(1),
    836                 entryType: EntryType.get(2),
     844                entryType: EntryType.get(3),
    837845                comment: "Checked up on it later and sensor is dropping out intermittently, created sub task to replace sensor.",
    838846                durationMinute: 20]
     
    933941        saveAndTest(inventoryLocation)
    934942
    935         inventoryLocation = new InventoryLocation(inventoryStore: InventoryStore.get(1), name: "C55")
     943        inventoryLocation = new InventoryLocation(inventoryStore: InventoryStore.get(2), name: "C55")
    936944        saveAndTest(inventoryLocation)
    937945    }
  • trunk/grails-app/services/TaskService.groovy

    r395 r418  
    3131    * Creates a new task with the given params.
    3232    * @param params The params to use when creating the new task.
    33     * @returns A map containing result.error=true (if any error) and result.taskInstance.
     33    * @returns A map containing result.error (if any error) and result.taskInstance.
    3434    */
    3535    def save(params) {
    3636        Task.withTransaction { status ->
    3737            def result = [:]
     38
     39            def fail = { Map m ->
     40                status.setRollbackOnly()
     41                if(result.taskInstance && m.field)
     42                    result.taskInstance.errors.rejectValue(m.field, m.code)
     43                result.error = [ code: m.code, args: ["Task", params.id] ]
     44                return result
     45            }
     46
    3847            // Default status to "not started" if not supplied.
    3948            params.taskStatus = params.taskStatus ?: TaskStatus.get(1)
    4049
    4150            // Set budgetStatus.
    42             if(params.taskType?.id?.toLong() == 1) // Unscheduled Breakin.
     51            if(params.taskType?.id?.toLong() == 1 || params.taskType?.id?.toLong() == 2) // Immediate Callout or Unsheduled Breakin.
    4352                params.taskBudgetStatus = params.taskBudgetStatus ?: TaskBudgetStatus.get(1) // Unplanned.
    4453            else
     
    4857            result.taskInstance = taskInstance
    4958
    50             if(result.taskInstance.parentTask?.trash) {
    51                 status.setRollbackOnly()
    52                 result.taskInstance.errors.rejectValue("parentTask", "task.operationNotPermittedOnTaskInTrash")
    53                 result.error = true
    54                 return result
    55             }
    56 
    57             if(taskInstance.save()) {
    58                 def taskModification = new TaskModification(person: authService.currentUser,
    59                                                         taskModificationType: TaskModificationType.get(1),
    60                                                         task: taskInstance)
    61 
    62                 if(!taskModification.save()) {
    63                     status.setRollbackOnly()
    64                     taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
    65                     result.error = true
    66                     return result
     59            if(result.taskInstance.parentTask?.trash)
     60                return fail(field:"parentTask", code:"task.operationNotPermittedOnTaskInTrash")
     61
     62            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
     63                return fail(code:"default.create.failure")
     64
     65            def taskModification = new TaskModification(person: authService.currentUser,
     66                                                taskModificationType: TaskModificationType.get(1),
     67                                                task: taskInstance)
     68
     69            if(taskModification.hasErrors() || !taskModification.save())
     70                return fail(field:"taskModifications", code:"task.modifications.failedToSave")
     71
     72            //Add the assignedGroups, provided by a new ArrayList(task.assignedGroups)
     73            if(params.assignedGroups) {
     74                def assignedGroupsResult
     75                def assignedGroupParams = [:]
     76                params.assignedGroups.each() {
     77
     78                    assignedGroupParams = [personGroup: it.personGroup,
     79                                                                task: taskInstance,
     80                                                                estimatedHour: it.estimatedHour,
     81                                                                estimatedMinute: it.estimatedMinute]
     82
     83                    assignedGroupsResult = assignedGroupService.save(assignedGroupParams)
     84
     85                    if(assignedGroupsResult.error)
     86                        return fail(field:"assignedGroups", code:"task.assignedGroups.failedToSave")
     87
    6788                }
    68 
    69                 //Add the assignedGroups, provided by a new ArrayList(task.assignedGroups)
    70                 if(params.assignedGroups) {
    71                     def assignedGroupsResult
    72                     def assignedGroupParams = [:]
    73                     params.assignedGroups.each() {
    74 
    75                         assignedGroupParams = [personGroup: it.personGroup,
    76                                                                     task: taskInstance,
    77                                                                     estimatedHour: it.estimatedHour,
    78                                                                     estimatedMinute: it.estimatedMinute]
    79 
    80                         assignedGroupsResult = assignedGroupService.save(assignedGroupParams)
    81 
    82                         if(assignedGroupsResult.error) {
    83                             status.setRollbackOnly()
    84                             taskInstance.errors.rejectValue("assignedGroups", "task.assignedGroups.failedToSave")
    85                             result.error = true
    86                             return result
    87                         }
    88 
    89                     }
     89            }
     90
     91            //Add the assignedPersons, provided by a new ArrayList(task.assignedPersons)
     92            if(params.assignedPersons) {
     93                def assignedPersonsResult
     94                def assignedPersonsParams = [:]
     95                params.assignedPersons.each() {
     96
     97                    assignedPersonsParams = [person: it.person,
     98                                                                task: taskInstance,
     99                                                                estimatedHour: it.estimatedHour,
     100                                                                estimatedMinute: it.estimatedMinute]
     101
     102                    assignedPersonsResult = assignedPersonService.save(assignedPersonsParams)
     103
     104                    if(assignedPersonsResult.error)
     105                        return fail(field:"assignedPersons", code:"task.assignedPersons.failedToSave")
     106
    90107                }
    91 
    92                 //Add the assignedPersons, provided by a new ArrayList(task.assignedPersons)
    93                 if(params.assignedPersons) {
    94                     def assignedPersonsResult
    95                     def assignedPersonsParams = [:]
    96                     params.assignedPersons.each() {
    97 
    98                         assignedPersonsParams = [person: it.person,
    99                                                                     task: taskInstance,
    100                                                                     estimatedHour: it.estimatedHour,
    101                                                                     estimatedMinute: it.estimatedMinute]
    102 
    103                         assignedPersonsResult = assignedPersonService.save(assignedPersonsParams)
    104 
    105                         if(assignedPersonsResult.error) {
    106                             status.setRollbackOnly()
    107                             taskInstance.errors.rejectValue("assignedPersons", "task.assignedPersons.failedToSave")
    108                             result.error = true
    109                             return result
    110                         }
    111 
    112                     }
    113                 }
    114 
    115                 // Success.
    116                 return result
    117             }
    118             else {
    119                 result.error = true
    120                 return result
    121             }
     108            }
     109
     110            // Success.
     111            return result
    122112
    123113        } //end withTransaction
     
    210200
    211201            // If task status is "Not Started" and entry type is "Work Done" then we create the started modification and set the status.
    212             if(taskInstance.taskStatus.id == 1 && result.entryInstance.entryType.id == 2) {
     202            if(taskInstance.taskStatus.id == 1 && result.entryInstance.entryType.id == 3) {
    213203
    214204                // Create the "Started" task modification, this provides the "Actual Started Date".
     
    239229    * Updates an existing task.
    240230    * @param params The params to update for task with id of params.id.
    241     * @returns A map containing result.error=true (if any error) and result.taskInstance (if available).
     231    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
    242232    */
    243233    def update(params) {
     
    245235            def result = [:]
    246236
    247             def fail = { Object[] args ->
    248                 status.setRollbackOnly()
    249                 if(args.size() == 2) result.taskInstance.errors.rejectValue(args[0], args[1])
    250                 result.error = true
     237            def fail = { Map m ->
     238                status.setRollbackOnly()
     239                if(result.taskInstance && m.field)
     240                    result.taskInstance.errors.rejectValue(m.field, m.code)
     241                result.error = [ code: m.code, args: ["Task", params.id] ]
    251242                return result
    252243            }
     
    259250            // Optimistic locking check.
    260251            if(params.version) {
    261                 def version = params.version.toLong()
    262                 if(result.taskInstance.version > version)
    263                     return fail("version", "default.optimistic.locking.failure")
     252                if(result.taskInstance.version > params.version.toLong())
     253                    return fail(field:"version", code:"default.optimistic.locking.failure")
    264254            }
    265255
     
    267257
    268258            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
    269                 return fail()
     259                return fail(code:"default.update.failure")
    270260
    271261            def taskModification = new TaskModification(person:authService.currentUser,
     
    273263                                                    task: result.taskInstance)
    274264
    275             if(!taskModification.save())
    276                 return fail("taskModifications", "task.modifications.failedToSave")
    277 
    278             // If we get here all went well.
     265            if(taskModification.hasErrors() || !taskModification.save())
     266                return fail(code:"task.modifications.failedToSave")
     267
     268            // Success.
    279269            return result
    280270
     
    285275    * Completes an existing task.
    286276    * @param params The params for task with id of params.id.
    287     * @returns A map containing result.error=true (if any error) and result.taskInstance.
     277    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
    288278    */
    289279    def complete(params) {
    290280        Task.withTransaction { status ->
    291281            def result = [:]
    292             result.taskInstance = Task.get(params.id)
    293             if(result.taskInstance) {
    294 
    295                 // Optimistic locking check.
    296                 if(params.version) {
    297                     def version = params.version.toLong()
    298                     if(result.taskInstance.version > version) {
    299                         status.setRollbackOnly()
    300                         result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
    301                         result.error = true
    302                         return result
    303                     }
    304                 }
    305 
    306                 result.taskInstance.taskStatus = TaskStatus.get(3)
    307                 result.taskInstance.taskRecurringSchedule?.enabled = false
    308 
    309                 if(result.taskInstance.save()) {
    310                     def taskModification = new TaskModification(person:authService.currentUser,
    311                                                             taskModificationType: TaskModificationType.get(4),
    312                                                             task: result.taskInstance)
    313 
    314                     if(taskModification.save()) {
    315                         // All went well.
    316                         return result
    317                     }
    318                     else {
    319                         status.setRollbackOnly()
    320                         result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
    321                         result.error = true
    322                         return result
    323                     }
    324                 }
    325             }
    326             // Something failed.
    327             status.setRollbackOnly()
    328             result.error = true
     282
     283            def fail = { Map m ->
     284                status.setRollbackOnly()
     285                if(result.taskInstance && m.field)
     286                    result.taskInstance.errors.rejectValue(m.field, m.code)
     287                result.error = [ code: m.code, args: ["Task", params.id] ]
     288                return result
     289            }
     290
     291            result.taskInstance = Task.get(params.id)
     292
     293            if(!result.taskInstance)
     294                return fail(code:"default.not.found")
     295
     296            // Optimistic locking check.
     297            if(params.version) {
     298                if(result.taskInstance.version > params.version.toLong())
     299                    return fail(field:"version", code:"default.optimistic.locking.failure")
     300            }
     301
     302            result.taskInstance.taskStatus = TaskStatus.get(3)
     303            result.taskInstance.attentionFlag = false
     304            result.taskInstance.taskRecurringSchedule?.enabled = false
     305
     306            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
     307                return fail(code:"default.update.failure")
     308
     309            def taskModification = new TaskModification(person:authService.currentUser,
     310                                                    taskModificationType: TaskModificationType.get(4),
     311                                                    task: result.taskInstance)
     312
     313
     314            if(taskModification.hasErrors() || !taskModification.save())
     315                return fail(code:"task.modifications.failedToSave")
     316
     317            // Success.
    329318            return result
    330319
    331320        } //end withTransaction
    332321    }  // end complete()
     322
     323    /**
     324    * Sets the attentionFlag on an existing task.
     325    * @param params The params for task with id of params.id.
     326    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
     327    */
     328    def setAttentionFlag(params) {
     329        Task.withTransaction { status ->
     330            def result = [:]
     331
     332            def fail = { Map m ->
     333                status.setRollbackOnly()
     334                if(result.taskInstance && m.field)
     335                    result.taskInstance.errors.rejectValue(m.field, m.code)
     336                result.error = [ code: m.code, args: ["Task", params.id] ]
     337                return result
     338            }
     339
     340            result.taskInstance = Task.get(params.id)
     341
     342            if(!result.taskInstance)
     343                return fail(code:"default.not.found")
     344
     345            // Optimistic locking check.
     346            if(params.version) {
     347                if(result.taskInstance.version > params.version.toLong())
     348                    return fail(field:"version", code:"default.optimistic.locking.failure")
     349            }
     350
     351            result.taskInstance.attentionFlag = true
     352
     353            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
     354                return fail(code:"default.update.failure")
     355
     356            def taskModification = new TaskModification(person:authService.currentUser,
     357                                                    taskModificationType: TaskModificationType.get(12),
     358                                                    task: result.taskInstance)
     359
     360            if(taskModification.hasErrors() || !taskModification.save())
     361                return fail(code:"task.modifications.failedToSave")
     362
     363            // Success.
     364            return result
     365
     366        } //end withTransaction
     367    }  // end flag()
     368
     369    /**
     370    * Clears the attentionFlag on an existing task.
     371    * @param params The params for task with id of params.id.
     372    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
     373    */
     374    def clearAttentionFlag(params) {
     375        Task.withTransaction { status ->
     376            def result = [:]
     377
     378            def fail = { Map m ->
     379                status.setRollbackOnly()
     380                if(result.taskInstance && m.field)
     381                    result.taskInstance.errors.rejectValue(m.field, m.code)
     382                result.error = [ code: m.code, args: ["Task", params.id] ]
     383                return result
     384            }
     385
     386            result.taskInstance = Task.get(params.id)
     387
     388            if(!result.taskInstance)
     389                return fail(code:"default.not.found")
     390
     391            // Optimistic locking check.
     392            if(params.version) {
     393                if(result.taskInstance.version > params.version.toLong())
     394                    return fail(field:"version", code:"default.optimistic.locking.failure")
     395            }
     396
     397            result.taskInstance.attentionFlag = false
     398
     399            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
     400                return fail(code:"default.update.failure")
     401
     402            def taskModification = new TaskModification(person:authService.currentUser,
     403                                                    taskModificationType: TaskModificationType.get(13),
     404                                                    task: result.taskInstance)
     405
     406            if(taskModification.hasErrors() || !taskModification.save())
     407                return fail(code:"task.modifications.failedToSave")
     408
     409            // Success.
     410            return result
     411
     412        } //end withTransaction
     413    }  // end clearFlag()
    333414
    334415    /**
    335416    * Reopens an existing task.
    336417    * @param params The params for task with id of params.id.
    337     * @returns A map containing result.error=true (if any error) and result.taskInstance.
     418    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
    338419    */
    339420    def reopen(params) {
    340421        Task.withTransaction { status ->
    341422            def result = [:]
    342             result.taskInstance = Task.get(params.id)
    343             if(result.taskInstance) {
    344 
    345                 // Optimistic locking check.
    346                 if(params.version) {
    347                     def version = params.version.toLong()
    348                     if(result.taskInstance.version > version) {
    349                         status.setRollbackOnly()
    350                         result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
    351                         result.error = true
    352                         return result
    353                     }
    354                 }
    355 
    356                 result.taskInstance.taskStatus = TaskStatus.get(2)
    357 
    358                 if(result.taskInstance.save()) {
    359                     def taskModification = new TaskModification(person:authService.currentUser,
    360                                                             taskModificationType: TaskModificationType.get(5),
    361                                                             task: result.taskInstance)
    362                     if(taskModification.save()) {
    363                         // All went well.
    364                         return result
    365                     }
    366                     else {
    367                         status.setRollbackOnly()
    368                         result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
    369                         result.error = true
    370                         return result
    371                     }
    372                 }
    373             }
    374             // Something failed.
    375             status.setRollbackOnly()
    376             result.error = true
     423
     424            def fail = { Map m ->
     425                status.setRollbackOnly()
     426                if(result.taskInstance && m.field)
     427                    result.taskInstance.errors.rejectValue(m.field, m.code)
     428                result.error = [ code: m.code, args: ["Task", params.id] ]
     429                return result
     430            }
     431
     432            result.taskInstance = Task.get(params.id)
     433
     434            if(!result.taskInstance)
     435                return fail(code:"default.not.found")
     436
     437            // Optimistic locking check.
     438            if(params.version) {
     439                if(result.taskInstance.version > params.version.toLong())
     440                    return fail(field:"version", code:"default.optimistic.locking.failure")
     441            }
     442
     443            result.taskInstance.taskStatus = TaskStatus.get(2)
     444
     445            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
     446                return fail(code:"default.update.failure")
     447
     448            def taskModification = new TaskModification(person:authService.currentUser,
     449                                                    taskModificationType: TaskModificationType.get(5),
     450                                                    task: result.taskInstance)
     451
     452            if(taskModification.hasErrors() || !taskModification.save())
     453                return fail(code:"task.modifications.failedToSave")
     454
     455            // Success.
    377456            return result
    378457
     
    383462    * Move a task to the trash.
    384463    * @param params The params for task with id of params.id.
    385     * @returns A map containing result.error=true (if any error) and result.taskInstance.
     464    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
    386465    */
    387466    def trash(params) {
    388467        Task.withTransaction { status ->
    389468            def result = [:]
    390             result.taskInstance = Task.get(params.id)
    391             if(result.taskInstance) {
    392 
    393                 // Optimistic locking check.
    394                 if(params.version) {
    395                     def version = params.version.toLong()
    396                     if(result.taskInstance.version > version) {
    397                         status.setRollbackOnly()
    398                         result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
    399                         result.error = true
    400                         return result
    401                     }
    402                 }
    403 
    404                 result.taskInstance.trash = true
    405                 result.taskInstance.taskRecurringSchedule?.enabled = false
    406 
    407                 if(result.taskInstance.save()) {
    408                     def taskModification = new TaskModification(person:authService.currentUser,
    409                                                             taskModificationType: TaskModificationType.get(6),
    410                                                             task: result.taskInstance)
    411                     if(taskModification.save()) {
    412                         // All went well.
    413                         return result
    414                     }
    415                     else {
    416                         status.setRollbackOnly()
    417                         result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
    418                         result.error = true
    419                         return result
    420                     }
    421                 }
    422             }
    423             // Something failed.
    424             status.setRollbackOnly()
    425             result.error = true
     469
     470            def fail = { Map m ->
     471                status.setRollbackOnly()
     472                if(result.taskInstance && m.field)
     473                    result.taskInstance.errors.rejectValue(m.field, m.code)
     474                result.error = [ code: m.code, args: ["Task", params.id] ]
     475                return result
     476            }
     477
     478            result.taskInstance = Task.get(params.id)
     479
     480            if(!result.taskInstance)
     481                return fail(code:"default.not.found")
     482
     483            // Optimistic locking check.
     484            if(params.version) {
     485                if(result.taskInstance.version > params.version.toLong())
     486                    return fail(field:"version", code:"default.optimistic.locking.failure")
     487            }
     488
     489            result.taskInstance.trash = true
     490            result.taskInstance.attentionFlag = false
     491            result.taskInstance.taskRecurringSchedule?.enabled = false
     492
     493            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
     494                return fail(code:"default.update.failure")
     495
     496            def taskModification = new TaskModification(person:authService.currentUser,
     497                                                    taskModificationType: TaskModificationType.get(6),
     498                                                    task: result.taskInstance)
     499
     500            if(taskModification.hasErrors() || !taskModification.save())
     501                return fail(code:"task.modifications.failedToSave")
     502
     503            // Success.
    426504            return result
    427505
     
    432510    * Restore a task from the trash.
    433511    * @param params The params for task with id of params.id.
    434     * @returns A map containing result.error=true (if any error) and result.taskInstance.
     512    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
    435513    */
    436514    def restore(params) {
    437515        Task.withTransaction { status ->
    438516            def result = [:]
    439             result.taskInstance = Task.get(params.id)
    440             if(result.taskInstance) {
    441 
    442                 // Optimistic locking check.
    443                 if(params.version) {
    444                     def version = params.version.toLong()
    445                     if(result.taskInstance.version > version) {
    446                         status.setRollbackOnly()
    447                         result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
    448                         result.error = true
    449                         return result
    450                     }
    451                 }
    452 
    453                 result.taskInstance.trash = false
    454 
    455                 if(result.taskInstance.save()) {
    456                     def taskModification = new TaskModification(person:authService.currentUser,
    457                                                             taskModificationType: TaskModificationType.get(7),
    458                                                             task: result.taskInstance)
    459                     if(taskModification.save()) {
    460                         // All went well.
    461                         return result
    462                     }
    463                     else {
    464                         status.setRollbackOnly()
    465                         result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
    466                         result.error = true
    467                         return result
    468                     }
    469                 }
    470             }
    471             // Something failed.
    472             status.setRollbackOnly()
    473             result.error = true
     517
     518            def fail = { Map m ->
     519                status.setRollbackOnly()
     520                if(result.taskInstance && m.field)
     521                    result.taskInstance.errors.rejectValue(m.field, m.code)
     522                result.error = [ code: m.code, args: ["Task", params.id] ]
     523                return result
     524            }
     525
     526            result.taskInstance = Task.get(params.id)
     527
     528            if(!result.taskInstance)
     529                return fail(code:"default.not.found")
     530
     531            // Optimistic locking check.
     532            if(params.version) {
     533                if(result.taskInstance.version > params.version.toLong())
     534                    return fail(field:"version", code:"default.optimistic.locking.failure")
     535            }
     536
     537            result.taskInstance.trash = false
     538
     539            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
     540                return fail(code:"default.update.failure")
     541
     542            def taskModification = new TaskModification(person:authService.currentUser,
     543                                                    taskModificationType: TaskModificationType.get(7),
     544                                                    task: result.taskInstance)
     545
     546            if(taskModification.hasErrors() || !taskModification.save())
     547                return fail(code:"task.modifications.failedToSave")
     548
     549            // Success.
    474550            return result
    475551
     
    480556    * Approve a task.
    481557    * @param params The params for task with id of params.id.
    482     * @returns A map containing result.error=true (if any error) and result.taskInstance.
     558    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
    483559    */
    484560    def approve(params) {
    485561        Task.withTransaction { status ->
    486562            def result = [:]
    487             result.taskInstance = Task.get(params.id)
    488             if(result.taskInstance) {
    489 
    490                 // Optimistic locking check.
    491                 if(params.version) {
    492                     def version = params.version.toLong()
    493                     if(result.taskInstance.version > version) {
    494                         status.setRollbackOnly()
    495                         result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
    496                         result.error = true
    497                         return result
    498                     }
    499                 }
    500 
    501                 result.taskInstance.approved = true
    502 
    503                 if(result.taskInstance.save()) {
    504                     def taskModification = new TaskModification(person:authService.currentUser,
    505                                                             taskModificationType: TaskModificationType.get(8),
    506                                                             task: result.taskInstance)
    507                     if(taskModification.save()) {
    508                         // All went well.
    509                         return result
    510                     }
    511                     else {
    512                         status.setRollbackOnly()
    513                         result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
    514                         result.error = true
    515                         return result
    516                     }
    517                 }
    518             }
    519             // Something failed.
    520             status.setRollbackOnly()
    521             result.error = true
     563
     564            def fail = { Map m ->
     565                status.setRollbackOnly()
     566                if(result.taskInstance && m.field)
     567                    result.taskInstance.errors.rejectValue(m.field, m.code)
     568                result.error = [ code: m.code, args: ["Task", params.id] ]
     569                return result
     570            }
     571
     572            result.taskInstance = Task.get(params.id)
     573
     574            if(!result.taskInstance)
     575                return fail(code:"default.not.found")
     576
     577            // Optimistic locking check.
     578            if(params.version) {
     579                if(result.taskInstance.version > params.version.toLong())
     580                    return fail(field:"version", code:"default.optimistic.locking.failure")
     581            }
     582
     583            result.taskInstance.approved = true
     584
     585            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
     586                return fail(code:"default.update.failure")
     587
     588            def taskModification = new TaskModification(person:authService.currentUser,
     589                                                    taskModificationType: TaskModificationType.get(8),
     590                                                    task: result.taskInstance)
     591
     592            if(taskModification.hasErrors() || !taskModification.save())
     593                return fail(code:"task.modifications.failedToSave")
     594
     595            // Success.
    522596            return result
    523597
     
    528602    * Remove a previously given approval from a task.
    529603    * @param params The params for task with id of params.id.
    530     * @returns A map containing result.error=true (if any error) and result.taskInstance.
     604    * @returns A map containing result.error (if any error) and result.taskInstance (if available).
    531605    */
    532606    def renegeApproval(params) {
    533607        Task.withTransaction { status ->
    534608            def result = [:]
    535             result.taskInstance = Task.get(params.id)
    536             if(result.taskInstance) {
    537 
    538                 // Optimistic locking check.
    539                 if(params.version) {
    540                     def version = params.version.toLong()
    541                     if(result.taskInstance.version > version) {
    542                         status.setRollbackOnly()
    543                         result.taskInstance.errors.rejectValue("version", "task.optimistic.locking.failure", "Another user has updated this Task while you were editing.")
    544                         result.error = true
    545                         return result
    546                     }
    547                 }
    548 
    549                 result.taskInstance.approved = false
    550 
    551                 if(result.taskInstance.save()) {
    552                     def taskModification = new TaskModification(person:authService.currentUser,
    553                                                             taskModificationType: TaskModificationType.get(9),
    554                                                             task: result.taskInstance)
    555                     if(taskModification.save()) {
    556                         // All went well.
    557                         return result
    558                     }
    559                     else {
    560                         status.setRollbackOnly()
    561                         result.taskInstance.errors.rejectValue("taskModifications", "task.modifications.failedToSave")
    562                         result.error = true
    563                         return result
    564                     }
    565                 }
    566             }
    567             // Something failed.
    568             status.setRollbackOnly()
    569             result.error = true
     609
     610            def fail = { Map m ->
     611                status.setRollbackOnly()
     612                if(result.taskInstance && m.field)
     613                    result.taskInstance.errors.rejectValue(m.field, m.code)
     614                result.error = [ code: m.code, args: ["Task", params.id] ]
     615                return result
     616            }
     617
     618            result.taskInstance = Task.get(params.id)
     619
     620            if(!result.taskInstance)
     621                return fail(code:"default.not.found")
     622
     623            // Optimistic locking check.
     624            if(params.version) {
     625                if(result.taskInstance.version > params.version.toLong())
     626                    return fail(field:"version", code:"default.optimistic.locking.failure")
     627            }
     628
     629            result.taskInstance.approved = false
     630
     631            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
     632                return fail(code:"default.update.failure")
     633
     634            def taskModification = new TaskModification(person:authService.currentUser,
     635                                                    taskModificationType: TaskModificationType.get(9),
     636                                                    task: result.taskInstance)
     637
     638            if(taskModification.hasErrors() || !taskModification.save())
     639                return fail(code:"task.modifications.failedToSave")
     640
     641            // Success.
    570642            return result
    571643
     
    574646
    575647    /**
    576     * Creates a new breakin task with the given params.
     648    * Creates a new immediate callout task with the given params.
    577649    * @param params The params to use when creating the new task.
    578     * @returns A map containing result.error=true (if any error) and result.taskInstance.
    579     */
    580     def saveBreakin(params) {
     650    * @returns A map containing result.error (if any error) and result.taskInstance.
     651    */
     652    def saveImmediateCallout(params) {
    581653        Task.withTransaction { status ->
    582654            def result = [:]
     
    596668            result.taskInstance = new Task(params)
    597669
    598             // Always for a breakin.
    599             result.taskInstance.taskType = TaskType.get(1) // Unscheduled Breakin.
     670            // Always for an immediate callout.
     671            result.taskInstance.taskType = TaskType.get(1) // Immediate Callout.
    600672            result.taskInstance.taskBudgetStatus = TaskBudgetStatus.get(1) // Unplanned.
    601673            result.taskInstance.taskPriority = TaskPriority.get(4) // Immediate.
     
    624696            result.entryFaultInstance = faultResult.entryInstance
    625697
     698            def causeParams = [task: result.taskInstance,
     699                                            entryType: EntryType.get(2),
     700                                            comment: params.entryCause.comment]
     701            def causeResult = saveEntry(causeParams)
     702            result.entryCauseInstance = causeResult.entryInstance
     703
    626704            def workDoneParams = [task: result.taskInstance,
    627                                                     entryType: EntryType.get(2),
     705                                                    entryType: EntryType.get(3),
    628706                                                    comment: params.entryWorkDone.comment,
    629707                                                    durationHour: params.entryWorkDone.durationHour,
     
    635713                return result
    636714
     715            if(causeResult.error)
     716                return fail(code: "default.create.failure")
     717
    637718            if(faultResult.error)
    638719                return fail(code: "default.create.failure")
     
    645726
    646727        } //end withTransaction
    647     } // end saveBreakin()
     728    } // end saveImmediateCallout()
    648729
    649730} // end TaskService
  • trunk/grails-app/views/taskDetailed/createImmediateCallout.gsp

    r406 r418  
    33        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    44        <meta name="layout" content="main" />
    5         <title>Create Breakin</title>
     5        <title>Create Immediate Callout</title>
    66        <nav:resources override="true"/>
    77        <resource:dateChooser />
     
    2323            </div>
    2424            </g:hasErrors>
     25            <g:hasErrors bean="${entryCauseInstance}">
     26            <div class="errors">
     27                <g:renderErrors bean="${entryCauseInstance}" as="list" />
     28            </div>
     29            </g:hasErrors>
    2530            <g:hasErrors bean="${entryWorkDoneInstance}">
    2631            <div class="errors">
     
    2934            </g:hasErrors>
    3035
    31             <g:form action="saveBreakin" method="post" name="createTaskForm">
     36            <g:form action="saveImmediateCallout" method="post" name="createTaskForm">
    3237                <div class="dialog">
    3338                    <table>
     
    3641                            <tr class="prop">
    3742                                <td valign="top" class="name">
    38                                     <label for="description">Breakin Description:</label>
     43                                    <label for="description">Callout Description:</label>
    3944                                </td>
    4045                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'description','errors')}">
     
    4247                                    <g:helpBalloon class="helpballoon" code="task.description" />
    4348                                </td>
     49                            </tr>
     50                       
     51                            <tr class="prop">
     52                                <td valign="top" class="name">
     53                                    <label for="durationHour">Down Time:</label>
     54                                </td>
     55
     56                                <td valign="top" class="value">
     57                                    <input class="time ${hasErrors(bean:entryFaultInstance,field:'durationHour','errors')}"
     58                                        type="text" id="entryFault.durationHour" name="entryFault.durationHour"
     59                                        value="${fieldValue(bean:entryFaultInstance,field:'durationHour')}" />
     60                                    :
     61                                    <input class="time ${hasErrors(bean:entryFaultInstance,field:'durationMinute','errors')}"
     62                                        type="text" id="entryFault.durationMinute" name="entryFault.durationMinute"
     63                                        value="${fieldValue(bean:entryFaultInstance,field:'durationMinute')}" />
     64                                    <g:helpBalloon code="entry.duration" />
     65                                </td>
    4466                            </tr>
    4567                       
     
    5678                            <tr class="prop">
    5779                                <td valign="top" class="name">
    58                                     <label for="durationHour">Fault Duration:</label>
     80                                    <label for="comment">${entryCauseInstance?.entryType.encodeAsHTML()}:</label>
    5981                                </td>
    60 
    61                                 <td valign="top" class="value">
    62                                     <input class="time ${hasErrors(bean:entryFaultInstance,field:'durationHour','errors')}"
    63                                         type="text" id="entryFault.durationHour" name="entryFault.durationHour"
    64                                         value="${fieldValue(bean:entryFaultInstance,field:'durationHour')}" />
    65                                     :
    66                                     <input class="time ${hasErrors(bean:entryFaultInstance,field:'durationMinute','errors')}"
    67                                         type="text" id="entryFault.durationMinute" name="entryFault.durationMinute"
    68                                         value="${fieldValue(bean:entryFaultInstance,field:'durationMinute')}" />
    69                                     <g:helpBalloon code="entry.duration" />
    70                                 </td>
     82                                <td valign="top" class="value ${hasErrors(bean:entryCauseInstance,field:'comment','errors')}">
     83                                    <textarea rows="5" cols="40" name="entryCause.comment">${fieldValue(bean:entryCauseInstance, field:'comment')}</textarea>
     84                                        <g:helpBalloon code="entry.comment.cause" />
     85                                </td>
    7186                            </tr>
    7287                       
  • trunk/grails-app/views/taskDetailed/search.gsp

    r356 r418  
    1414
    1515        <div class="body">
    16             <g:if test="${flash.message}">
    17                 <div class="message">${flash.message}</div>
    18             </g:if>
     16            <g:render template="/shared/messages" />
    1917            <g:if test="${params.message}">
    2018                <div class="message">${params.message}</div>
     
    9189                        <tr>
    9290
     91                            <custom:sortableColumnWithImg property="attentionFlag"
     92                                                                                            imgSrc="${resource(dir:'images/skin',file:'flag_red.png')}"
     93                                                                                            imgAlt="Flag" params="${filterParams}" />
     94
    9395                            <g:sortableColumn property="id" title="Id" params="${filterParams}" />
    9496
     
    9698
    9799                            <g:sortableColumn property="description" title="Description" params="${filterParams}" />
    98 
    99                             <g:sortableColumn  property="leadPerson" title="Lead Person" params="${filterParams}" />
    100100
    101101                            <g:sortableColumn  property="taskPriority" title="Task Priority" params="${filterParams}" />
     
    111111                    <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}" onclick='window.location = "${request.getContextPath()}/taskDetailed/show/${taskInstance.id}"'/>
    112112
    113                             <td>${fieldValue(bean:taskInstance, field:'id')}</td>
     113                            <td class="idColumn">
     114                                <g:if test="${taskInstance.attentionFlag}">
     115                                    <img  src="${resource(dir:'images/skin',file:'flag_red.png')}" alt="Flag" />
     116                                </g:if>
     117                            </td>
     118
     119                            <td class="idColumn">${fieldValue(bean:taskInstance, field:'id')}</td>
    114120
    115121                            <td><g:formatDate date="${taskInstance.targetStartDate}" format="EEE, dd-MMM-yyyy"/></td>
    116122
    117123                            <td>${fieldValue(bean:taskInstance, field:'description')}</td>
    118 
    119                             <td>${fieldValue(bean:taskInstance, field:'leadPerson')}</td>
    120124
    121125                            <td>${fieldValue(bean:taskInstance, field:'taskPriority')}</td>
  • trunk/grails-app/views/taskDetailed/show.gsp

    r410 r418  
    1212        </div>
    1313        <div class="body">
    14             <g:if test="${flash.message}">
    15             <div class="message">${flash.message}</div>
    16             </g:if>
     14            <g:render template="/shared/messages" />
    1715            <g:if test="${taskInstance.trash}" >
    1816                <div class="errors">
    19                         This task is in the trash bin, but can be restored if required.
     17                        <ul><li>This task is in the trash bin, but can be restored if required.<li><ul>
    2018                </div>
    2119            </g:if>
     
    2624            </g:hasErrors>
    2725
     26            <div class="tabHeader">
     27                <h1 class="taskHeader">
     28                    Task #${taskInstance.id}
     29                    <g:if test="${taskInstance.attentionFlag}" >
     30                        <img  src="${resource(dir:'images/skin',file:'flag_red.png')}" alt="Flag" />
     31                    </g:if>
     32                    <g:if test="${taskInstance.taskStatus.id == 3}" >
     33                        <img  src="${resource(dir:'images/skin',file:'tick.png')}" alt="Flag" />
     34                    </g:if>
     35                </h1>
     36                ${fieldValue(bean:taskInstance, field:'description')}
     37            </div>
     38
     39            <br/>
     40
    2841            <richui:tabView id="tabView">
    2942
    3043                <richui:tabLabels>
    31                     <richui:tabLabel selected="${showTab.task}" title="Task #${taskInstance.id}" />
     44                    <richui:tabLabel selected="${showTab.task}" title="Details" />
    3245                    <richui:tabLabel selected="${showTab.procedure}" title="Procedure" />
    3346                    <richui:tabLabel selected="${showTab.recurrence}" title="Recurrence" />
     
    5366                                        </tr>
    5467                                    </g:if>
    55 
    56                                     <tr class="prop">
    57                                         <td valign="top" class="name">Description:</td>
    58 
    59                                         <td valign="top" class="value">${fieldValue(bean:taskInstance, field:'description')}</td>
    60 
    61                                     </tr>
    6268
    6369                                    <tr class="prop">
     
    224230
    225231                                    <g:if test="${taskInstance.taskStatus.id != 3}" >
    226                                         <span class="button"><g:actionSubmit class="complete" value="Complete" /></span>
     232
     233                                        <g:if test="${taskInstance.attentionFlag}" >
     234                                            <span class="button"><g:actionSubmit class="flag" value="Clear" action="clearAttentionFlag"/></span>
     235                                        </g:if>
     236                                        <g:else>
     237                                            <span class="button"><g:actionSubmit class="flag" value="Unresolved" action="setAttentionFlag"/></span>
     238                                        </g:else>
     239
     240                                        <span class="button"><g:actionSubmit class="complete" value="Resolved" action="complete"/></span>
    227241
    228242                                        <g:if test="${taskInstance.approved}" >
     
    259273                                            <th>Comment</th>
    260274                                            <th>Date Done</th>
    261                                             <th>Duration</th>
     275                                            <th>Down Time</th>
    262276                                            <th>Entered By</th>
    263277                                            <th></th>
     
    292306                                <span class="button">
    293307                                    <g:actionSubmit value="Add Fault" action="create"  class="add"/>
     308                                </span>
     309                            </g:form>
     310                        </div>
     311
     312                        <br />
     313
     314                        <g:if test="${entryCauseList.isEmpty()}">
     315                            <h1>No Causes</h1>
     316                            <br />
     317                        </g:if>
     318                        <g:else>
     319                            <div class="list">
     320                                <h1>Causes</h1>
     321                                <table>
     322                                    <thead>
     323                                        <tr>
     324                                            <th>Comment</th>
     325                                            <th>Date Done</th>
     326                                            <th>Entered By</th>
     327                                            <th></th>
     328                                        </tr>
     329                                    </thead>
     330                                    <tbody>
     331                                        <g:each in="${entryCauseList}" status="i" var="entry">
     332                                                <tr class="${(i % 2) == 0 ? 'clickableOdd' : 'clickableEven'}" onclick='window.location = "${request.getContextPath()}/entryDetailed/edit/${entry.id}"'/>
     333
     334                                                    <td style="width:65%">${entry.comment}</td>
     335                                                    <td><g:formatDate date="${entry.dateDone}" format="EEE, dd-MMM-yyyy"/></td>
     336                                                    <td>${entry.enteredBy}</td>
     337
     338                                                    <td>
     339                                                        <g:link controller="entryDetailed" action="edit" id="${entry.id}">
     340                                                            <img  src="${resource(dir:'images/skin',file:'database_edit.png')}" alt="Edit" />
     341                                                        </g:link>
     342                                                    </td>
     343
     344                                                </tr>
     345                                        </g:each>
     346                                    </tbody>
     347                                </table>
     348                            </div>
     349                        </g:else>
     350
     351                        <div class="buttons">
     352                            <g:form controller="entryDetailed">
     353                                <g:hiddenField name="taskInstance.id" value="${taskInstance?.id}" />
     354                                <g:hiddenField name="entryType.id" value="2" />
     355                                <span class="button">
     356                                    <g:actionSubmit value="Add Cause" action="create"  class="add"/>
    294357                                </span>
    295358                            </g:form>
     
    340403                            <g:form controller="entryDetailed">
    341404                                <g:hiddenField name="taskInstance.id" value="${taskInstance?.id}" />
    342                                 <g:hiddenField name="entryType.id" value="2" />
     405                                <g:hiddenField name="entryType.id" value="3" />
    343406                                <span class="button">
    344407                                    <g:actionSubmit value="Add Work Done" action="create"  class="add"/>
     
    687750            </richui:tabView>
    688751
    689         </div>
     752        </div> <!--body-->
    690753    </body>
    691754</html>
  • trunk/web-app/css/main.css

    r358 r418  
    5757}
    5858
     59/* Application log textarea */
    5960#log {
    6061    width: 920px;
     
    6263}
    6364
     65div.tabHeader {
     66    padding: 5px 15px 40px 15px;
     67    margin-bottom: -45px;
     68}
     69.tabHeader h1 {
     70    color: #2647a0;
     71    font-weight: bold;
     72    font-size: 17px;
     73    margin: 0 0 .3em 0;
     74}
     75.tabHeader h2 {
     76    color: #2647a0;
     77    font-weight: normal;
     78    font-size: 15px;
     79    margin: 0 0 .3em 0;
     80}
     81
    6482a:link, a:visited, a:hover {
    6583    color: #006dba;
     
    7694    font-weight: normal;
    7795    font-size: 17px;
     96    margin: 0 0 .3em 0;
     97}
     98
     99h2 {
     100    color: #006dba;
     101    font-weight: bold;
     102    font-size: 15px;
     103    margin: 0 0 .3em 0;
     104}
     105
     106h3 {
     107    color: #006dba;
     108    font-weight: normal;
     109    font-size: 15px;
    78110    margin: 0 0 .3em 0;
    79111}
     
    241273    text-align: left;
    242274    vertical-align: top;
     275}
     276td.idColumn {
     277    width: 25px;
    243278}
    244279th {
     
    400435.buttons input.complete {
    401436    background: transparent url(../images/skin/tick.png) 5px 50% no-repeat;
     437    padding-left: 28px;
     438}
     439.buttons input.flag {
     440    background: transparent url(../images/skin/flag_red.png) 5px 50% no-repeat;
    402441    padding-left: 28px;
    403442}
Note: See TracChangeset for help on using the changeset viewer.