Index: /trunk/grails-app/conf/Config.groovy
===================================================================
--- /trunk/grails-app/conf/Config.groovy	(revision 394)
+++ /trunk/grails-app/conf/Config.groovy	(revision 395)
@@ -147,4 +147,5 @@
             [order:11, controller:'taskDetailed', title:'Calendar', action:'searchCalendar', isVisible: { true }],
             [order:20, controller:'taskDetailed', title:'Create', action:'create', isVisible: { true }],
+            [order:30, controller:'taskDetailed', title:'Breakin', action:'createBreakin', isVisible: { true }],
             [order:90, controller:'taskDetailed', title:'Show', action:'show', isVisible: { params.action == 'show' }],
             [order:91, controller:'taskDetailed', title:'Edit', action:'edit', isVisible: { params.action == 'edit' }]
Index: /trunk/grails-app/controllers/TaskDetailedController.groovy
===================================================================
--- /trunk/grails-app/controllers/TaskDetailedController.groovy	(revision 394)
+++ /trunk/grails-app/controllers/TaskDetailedController.groovy	(revision 395)
@@ -586,3 +586,35 @@
     }
 
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def createBreakin = {
+        def taskInstance = new Task()
+
+        def entryFaultInstance = new Entry(entryType: EntryType.get(1))  // Fault.
+        def entryWorkDoneInstance = new Entry(entryType: EntryType.get(2))  // Work Done.
+
+        return ['taskInstance': taskInstance,
+                        'entryFaultInstance': entryFaultInstance,
+                        'entryWorkDoneInstance': entryWorkDoneInstance]
+    }
+
+    @Secured(['ROLE_AppAdmin', 'ROLE_Manager', 'ROLE_TaskManager', 'ROLE_TaskUser'])
+    def saveBreakin = {
+        def result = taskService.saveBreakin(params)
+
+        if(!result.error) {
+            flash.message = "Task ${result.taskInstance.id} created."
+            redirect(action: 'show', id: result.taskInstance.id)
+            return
+        }
+
+        if(result.error.code == "task.modifications.failedToSave")
+            flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
+
+        render(view:'createBreakin',
+                    model: ['taskInstance': result.taskInstance,
+                                'entryFaultInstance': result.entryFaultInstance,
+                                'entryWorkDoneInstance': result.entryWorkDoneInstance])
+
+    }
+
 } // end of class.
Index: /trunk/grails-app/services/TaskService.groovy
===================================================================
--- /trunk/grails-app/services/TaskService.groovy	(revision 394)
+++ /trunk/grails-app/services/TaskService.groovy	(revision 395)
@@ -182,64 +182,54 @@
         Task.withTransaction { status ->
             def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Entry", params.id] ]
+                return result
+            }
+
             result.entryInstance = new Entry(params)
             result.entryInstance.enteredBy = authService.currentUser
 
-            if(result.entryInstance.validate()) {
+            def taskInstance
+            if(result.entryInstance.task.id) {
                 result.taskId = result.entryInstance.task.id
-                def taskInstance = Task.lock(result.taskId)
-
-                if(!taskInstance) {
-                    status.setRollbackOnly()
-                    result.entryInstance.errors.rejectValue('task', "task.notFound")
-                    result.error = true
-                    return result
-                }
-
-                if(taskInstance.taskStatus.id == 3) {
-                    status.setRollbackOnly()
-                    result.entryInstance.errors.rejectValue('task', "task.operationNotPermittedOnCompleteTask")
-                    result.error = true
-                    return result
-                }
-
-                // If task status is "Not Started" and entry type is "Work Done" then we create the started modification and set the status.
-                if(taskInstance.taskStatus.id == 1 && result.entryInstance.entryType.id == 2) {
-
-                    // Create the "Started" task modification, this provides the "Actual started date".
-                    def taskModification = new TaskModification(person: authService.currentUser,
-                                                            taskModificationType: TaskModificationType.get(2),
-                                                            task: taskInstance)
-
-                    if(!taskModification.save()) {
-                        status.setRollbackOnly()
-                        taskInstance.errors.rejectValue("task", "task.modifications.failedToSave")
-                        result.error = true
-                        return result
-                    }
-
-                    // Set task status to "In progress".
-                    taskInstance.taskStatus = TaskStatus.get(2)
-
-                    if(!taskInstance.save()) {
-                        status.setRollbackOnly()
-                        result.entryInstance.errors.rejectValue("task", "task.failedToSave")
-                        result.error = true
-                        return result
-                    }
-                }
-
-                if(!result.entryInstance.save()) {
-                    status.setRollbackOnly()
-                    result.error = true
-                    return result
-                }
-
-                // If we get here all went well.
-                return result
-            }
-            else {
-                result.error = true
-                return result
-            }
+                taskInstance = Task.lock(result.entryInstance.task.id)
+            }
+
+            if(!taskInstance)
+                return fail(field:"task", code:"task.notFound")
+
+            if(result.entryInstance.hasErrors() || !result.entryInstance.save())
+                return fail(code:"default.create.failure")
+
+            if(taskInstance.taskStatus.id == 3)
+                return fail(field:"task", code:"task.operationNotPermittedOnCompleteTask")
+
+            // If task status is "Not Started" and entry type is "Work Done" then we create the started modification and set the status.
+            if(taskInstance.taskStatus.id == 1 && result.entryInstance.entryType.id == 2) {
+
+                // Create the "Started" task modification, this provides the "Actual Started Date".
+                def taskModification = new TaskModification(person: authService.currentUser,
+                                                        taskModificationType: TaskModificationType.get(2),
+                                                        task: taskInstance)
+
+                if(taskModification.hasErrors() || !taskModification.save())
+                    return fail(field:"task", code:"task.modifications.failedToSave")
+
+                // Set task status to "In Progress".
+                taskInstance.taskStatus = TaskStatus.get(2)
+
+                if(taskInstance.hasErrors() || !taskInstance.save())
+                    return fail(field:"task", code:"task.failedToSave")
+            }
+
+            if(result.entryInstance.hasErrors() || !result.entryInstance.save())
+                return fail(field:"task", code:"default.create.failure")
+
+            // Success.
+            return result
 
         } //end withTransaction
@@ -583,3 +573,77 @@
     }  // end renegeApproval()
 
+    /**
+    * Creates a new breakin task with the given params.
+    * @param params The params to use when creating the new task.
+    * @returns A map containing result.error=true (if any error) and result.taskInstance.
+    */
+    def saveBreakin(params) {
+        Task.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskInstance && m.field)
+                    result.taskInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Task", params.id] ]
+                return result
+            }
+
+            // If not supplied.
+            if(!params.taskStatus)
+                params.taskStatus = TaskStatus.get(1) // Not Started.
+
+            result.taskInstance = new Task(params)
+
+            // Always for a breakin.
+            result.taskInstance.taskType = TaskType.get(1) // Unscheduled Breakin.
+            result.taskInstance.taskBudgetStatus = TaskBudgetStatus.get(1) // Unplanned.
+            result.taskInstance.taskPriority = TaskPriority.get(4) // Immediate.
+            result.taskInstance.taskGroup = TaskGroup.get(1) // Engineering Activites.
+            result.taskInstance.approved = true
+            result.taskInstance.leadPerson = authService.currentUser
+
+            if(result.taskInstance.hasErrors() || !result.taskInstance.save())
+                fail(code:"default.create.failure")
+
+            if(!result.error) {
+                def taskModification = new TaskModification(person: authService.currentUser,
+                                                                taskModificationType: TaskModificationType.get(1), // Created.
+                                                                task: result.taskInstance)
+
+                if(taskModification.hasErrors() || !taskModification.save())
+                    fail(field:"taskModifications", code:"task.modifications.failedToSave")
+            }
+
+            def faultParams = [task: result.taskInstance,
+                                            entryType: EntryType.get(1),
+                                            comment: params.entryFault.comment,
+                                            durationHour: params.entryFault.durationHour,
+                                            durationMinute: params.entryFault.durationMinute]
+            def faultResult = saveEntry(faultParams)
+            result.entryFaultInstance = faultResult.entryInstance
+
+            def workDoneParams = [task: result.taskInstance,
+                                                    entryType: EntryType.get(2),
+                                                    comment: params.entryWorkDone.comment,
+                                                    durationHour: params.entryWorkDone.durationHour,
+                                                    durationMinute: params.entryWorkDone.durationMinute]
+            def workDoneResult = saveEntry(workDoneParams)
+            result.entryWorkDoneInstance = workDoneResult.entryInstance
+
+            if(result.error)
+                return result
+
+            if(faultResult.error)
+                return fail(code: "default.create.failure")
+
+            if(workDoneResult.error)
+                return fail(code: "default.create.failure")
+
+            // Success.
+            return result
+
+        } //end withTransaction
+    } // end saveBreakin()
+
 } // end TaskService
Index: /trunk/grails-app/views/entryDetailed/edit.gsp
===================================================================
--- /trunk/grails-app/views/entryDetailed/edit.gsp	(revision 394)
+++ /trunk/grails-app/views/entryDetailed/edit.gsp	(revision 395)
@@ -105,4 +105,5 @@
                 <div class="buttons">
                     <span class="button"><g:actionSubmit class="save" value="Update" /></span>
+                    <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
                     <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
                 </div>
Index: /trunk/grails-app/views/taskDetailed/createBreakin.gsp
===================================================================
--- /trunk/grails-app/views/taskDetailed/createBreakin.gsp	(revision 395)
+++ /trunk/grails-app/views/taskDetailed/createBreakin.gsp	(revision 395)
@@ -0,0 +1,132 @@
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Create Breakin</title>
+        <nav:resources override="true"/>
+        <resource:dateChooser />
+    </head>
+    <body onload="document.createTaskForm.description.focus();">
+        <div class="nav">
+            <nav:renderSubItems group="nav"/>
+        </div>
+        <div class="body">
+            <g:render template="/shared/messages" />
+            <g:hasErrors bean="${taskInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${taskInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:hasErrors bean="${entryFaultInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${entryFaultInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+            <g:hasErrors bean="${entryWorkDoneInstance}">
+            <div class="errors">
+                <g:renderErrors bean="${entryWorkDoneInstance}" as="list" />
+            </div>
+            </g:hasErrors>
+
+            <g:form action="saveBreakin" method="post" name="createTaskForm">
+                <div class="dialog">
+                    <table>
+                        <tbody>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="description">Breakin Description:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'description','errors')}">
+                                    <input type="text"  class="description" maxlength="75" id="description" name="description" value="${fieldValue(bean:taskInstance,field:'description')}"/>
+                                    <g:helpBalloon class="helpballoon" code="task.description" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">${entryFaultInstance?.entryType.encodeAsHTML()}:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryFaultInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="entryFault.comment">${fieldValue(bean:entryFaultInstance, field:'comment')}</textarea>
+                                        <g:helpBalloon code="entry.comment.fault" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="durationHour">Fault Duration:</label>
+                                </td>
+
+                                <td valign="top" class="value">
+                                    <input class="time ${hasErrors(bean:entryFaultInstance,field:'durationHour','errors')}"
+                                        type="text" id="entryFault.durationHour" name="entryFault.durationHour"
+                                        value="${fieldValue(bean:entryFaultInstance,field:'durationHour')}" />
+                                    :
+                                    <input class="time ${hasErrors(bean:entryFaultInstance,field:'durationMinute','errors')}"
+                                        type="text" id="entryFault.durationMinute" name="entryFault.durationMinute" 
+                                        value="${fieldValue(bean:entryFaultInstance,field:'durationMinute')}" />
+                                    <g:helpBalloon code="entry.duration" />
+                                </td> 
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="comment">${entryWorkDoneInstance?.entryType.encodeAsHTML()}:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:entryWorkDoneInstance,field:'comment','errors')}">
+                                    <textarea rows="5" cols="40" name="entryWorkDone.comment">${fieldValue(bean:entryWorkDoneInstance, field:'comment')}</textarea>
+                                        <g:helpBalloon code="entry.comment.work.done" />
+                                </td>
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="durationHour">Work Duration:</label>
+                                </td>
+
+                                <td valign="top" class="value">
+                                    <input class="time ${hasErrors(bean:entryWorkDoneInstance,field:'durationHour','errors')}"
+                                        type="text" id="entryWorkDone.durationHour" name="entryWorkDone.durationHour"
+                                        value="${fieldValue(bean:entryWorkDoneInstance,field:'durationHour')}" />
+                                    :
+                                    <input class="time ${hasErrors(bean:entryWorkDoneInstance,field:'durationMinute','errors')}"
+                                        type="text" id="entryWorkDone.durationMinute" name="entryWorkDone.durationMinute" 
+                                        value="${fieldValue(bean:entryWorkDoneInstance,field:'durationMinute')}" />
+                                    <g:helpBalloon code="entry.duration" />
+                                </td> 
+                            </tr>
+                        
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="primaryAsset">Primary Asset:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'primaryAsset','errors')}">
+                                    <g:select optionKey="id" from="${Asset.list()}" name="primaryAsset.id" value="${taskInstance?.primaryAsset?.id}" noSelection="['null':'--None--']"></g:select>
+                                    <g:helpBalloon code="task.primaryAsset" />
+                                </td>
+                            </tr>
+
+                            <tr class="prop">
+                                <td valign="top" class="name">
+                                    <label for="associatedAssets">Associated Assets:</label>
+                                </td>
+                                <td valign="top" class="value ${hasErrors(bean:taskInstance,field:'associatedAssets','errors')}">
+                                    <g:select id="associatedAssets" name="associatedAssets"
+                                                    from="${Asset.list()}"
+                                                    size="5" multiple="yes" optionKey="id"
+                                                    value="${taskInstance?.associatedAssets?.id}"  noSelection="['':'--None--']"/>
+                                    <g:helpBalloon code="task.associatedAssets" />
+                                </td>
+                            </tr>
+                        
+                        </tbody>
+                    </table>
+                </div>
+                <div class="buttons">
+                    <span class="button"><input class="save" type="submit" value="Create" /></span>
+                </div>
+            </g:form>
+        </div>
+    </body>
+</html>
