Index: trunk/grails-app/controllers/InventoryItemDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/InventoryItemDetailedController.groovy	(revision 424)
+++ trunk/grails-app/controllers/InventoryItemDetailedController.groovy	(revision 425)
@@ -238,6 +238,8 @@
         def result = inventoryItemService.edit(params)
 
-        if(!result.error)
-            return [ inventoryItemInstance : result.inventoryItemInstance ]
+        if(!result.error) {
+            def possibleAlternateItems = inventoryItemService.getPossibleAlternateItems(result.inventoryItemInstance)
+            return [ inventoryItemInstance : result.inventoryItemInstance, possibleAlternateItems: possibleAlternateItems]
+        }
 
         flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
@@ -260,5 +262,6 @@
         }
 
-        render(view:'edit', model:[inventoryItemInstance: result.inventoryItemInstance.attach()])
+        def possibleAlternateItems = inventoryItemService.getPossibleAlternateItems(result.inventoryItemInstance)
+        render(view:'edit', model:[inventoryItemInstance: result.inventoryItemInstance.attach(), possibleAlternateItems: possibleAlternateItems])
     }
 
Index: trunk/grails-app/domain/InventoryItem.groovy
===================================================================
--- trunk/grails-app/domain/InventoryItem.groovy	(revision 424)
+++ trunk/grails-app/domain/InventoryItem.groovy	(revision 425)
@@ -56,3 +56,27 @@
 
     String toString() {"${this.name}"}
+
+    def afterInsert = {
+        addReverseAlternateItems()
+    }
+
+    // Add reverse alternateItem references.
+    def addReverseAlternateItems() {
+        this.alternateItems.each() {
+            if( !it.alternateItems?.contains(this) )
+                it.addToAlternateItems(this)
+        }
+    }
+
+    /**
+   * Remove all reverse alternateItem references.
+    * Update: reverse alternateItem handling must be done in the
+    * service class since the before assignment alternateItems are required.
+    */
+    def removeReverseAlternateItems(alternateItems = this.alternateItems) {
+        alternateItems.each() {
+            it.removeFromAlternateItems(this)
+        }
+    }
+
 }
Index: trunk/grails-app/i18n/messages.properties
===================================================================
--- trunk/grails-app/i18n/messages.properties	(revision 424)
+++ trunk/grails-app/i18n/messages.properties	(revision 425)
@@ -123,4 +123,5 @@
 inventoryMovement.quantity.insufficientItemsInStock=Could not complete operation, insufficient items in stock.
 inventoryMovement.inventoryItem.notFound=Inventory Item not found.
+inventoryMovement.still.associated=Could not complete operation as inventory movements are still associated with this item.
 
 assignedGroup.task.not.found=Please select a task and then ''Add Assigned Group''.
Index: trunk/grails-app/services/InventoryItemService.groovy
===================================================================
--- trunk/grails-app/services/InventoryItemService.groovy	(revision 424)
+++ trunk/grails-app/services/InventoryItemService.groovy	(revision 425)
@@ -5,4 +5,17 @@
 
     boolean transactional = false
+
+    /**
+    * Prepare a sorted list of possible alternateItems.
+    */
+    def getPossibleAlternateItems(inventoryItemInstance) {
+        def criteria = inventoryItemInstance.createCriteria()
+        def possibleAlternateItems = criteria {
+            and {
+                eq('isActive', true)
+                notEqual('id', inventoryItemInstance.id)
+            }
+        }.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }
+    }
 
     /**
@@ -50,24 +63,35 @@
 
     def delete(params) {
-        def result = [:]
-        def fail = { Map m ->
-            result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
-            return result
-        }
+        InventoryItem.withTransaction { status ->
+            def result = [:]
 
-        result.inventoryItemInstance = InventoryItem.get(params.id)
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.inventoryItemInstance && m.field)
+                    result.inventoryItemInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["InventoryItem", params.id] ]
+                return result
+            }
 
-        if(!result.inventoryItemInstance)
-            return fail(code:"default.not.found")
+            result.inventoryItemInstance = InventoryItem.get(params.id)
 
-        try {
-            result.inventoryItemInstance.delete(flush:true)
-            return result //Success.
-        }
-        catch(org.springframework.dao.DataIntegrityViolationException e) {
-            return fail(code:"default.delete.failure")
-        }
+            if(!result.inventoryItemInstance)
+                return fail(code:"default.not.found")
 
-    }
+            if(result.inventoryItemInstance.inventoryMovements)
+                return fail(code:"inventoryMovement.still.associated")
+
+            result.inventoryItemInstance.removeReverseAlternateItems()
+
+            try {
+                result.inventoryItemInstance.delete(flush:true)
+                return result //Success.
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                return fail(code:"default.delete.failure")
+            }
+
+        } //end withTransaction
+    } // end delete()
 
     def edit(params) {
@@ -110,8 +134,13 @@
             }
 
+            def previousAlternateItems = new ArrayList(result.inventoryItemInstance.alternateItems)
+
             result.inventoryItemInstance.properties = params
 
             if(result.inventoryItemInstance.hasErrors() || !result.inventoryItemInstance.save())
                 return fail(code:"default.update.failure")
+
+            result.inventoryItemInstance.removeReverseAlternateItems(previousAlternateItems)
+            result.inventoryItemInstance.addReverseAlternateItems()
 
             // Success.
@@ -158,4 +187,3 @@
     }
 
-
 } // end class
Index: trunk/grails-app/views/inventoryItemDetailed/edit.gsp
===================================================================
--- trunk/grails-app/views/inventoryItemDetailed/edit.gsp	(revision 424)
+++ trunk/grails-app/views/inventoryItemDetailed/edit.gsp	(revision 425)
@@ -238,5 +238,5 @@
                                 <td valign="top" class="value ${hasErrors(bean:inventoryItemInstance,field:'alternateItems','errors')}">
                                     <g:select name="alternateItems"
-                                                        from="${ InventoryItem.list().sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }"
+                                                        from="${possibleAlternateItems}"
                                                         size="5" multiple="yes" optionKey="id"
                                                         value="${inventoryItemInstance?.alternateItems.id}" noSelection="['':'--None--']"/>
Index: trunk/grails-app/views/inventoryItemDetailed/show.gsp
===================================================================
--- trunk/grails-app/views/inventoryItemDetailed/show.gsp	(revision 424)
+++ trunk/grails-app/views/inventoryItemDetailed/show.gsp	(revision 425)
@@ -149,5 +149,5 @@
                                         <td  valign="top" style="text-align:left;" class="value">
                                             <ul>
-                                            <g:each var="a" in="${inventoryItemInstance.alternateItems}">
+                                            <g:each var="a" in="${ inventoryItemInstance.alternateItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) } }">
                                                 <li><g:link controller="inventoryItemDetailed" action="show" id="${a.id}">${a?.encodeAsHTML()}</g:link></li>
                                             </g:each>
