Index: trunk/grails-app/services/AssetService.groovy
===================================================================
--- trunk/grails-app/services/AssetService.groovy	(revision 352)
+++ trunk/grails-app/services/AssetService.groovy	(revision 360)
@@ -47,4 +47,5 @@
                     r = assetSubItemService.delete(id: assetSubItem.id)
                     if(r.error) {
+                        log.debug r.error
                         fail(code:"asset.subItems.delete.failure")
                         break
@@ -56,11 +57,11 @@
                 return result
 
-            try {
-                result.assetInstance.delete(flush:true)
-                return result //Success.
-            }
-            catch(org.springframework.dao.DataIntegrityViolationException e) {
-                return fail(code:"default.delete.failure")
-            }
+            // Success.
+            // We have handled all the foreign keys so the delete should go forward.
+            // Can't flush here due to cascading from Section and Site.
+            // And without flush there is no point it trying to catch the dao.DataIntegrityViolationException
+            // since that will only happen after leaving the transaction.
+            result.assetInstance.delete()
+            return result
 
         } // end withTransaction
Index: trunk/grails-app/services/AssetSubItemService.groovy
===================================================================
--- trunk/grails-app/services/AssetSubItemService.groovy	(revision 352)
+++ trunk/grails-app/services/AssetSubItemService.groovy	(revision 360)
@@ -21,29 +21,42 @@
 
     def delete(params) {
-        def result = [:]
-        def fail = { Map m ->
-            result.error = [ code: m.code, args: ["AssetSubItem", params.id] ]
-            return result
-        }
+        AssetSubItem.withTransaction { status ->
+            def result = [:]
 
-        result.assetSubItemInstance = AssetSubItem.get(params.id)
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.assetSubItemInstance && m.field)
+                    result.assetSubItemInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["AssetSubItem", params.id] ]
+                return result
+            }
 
-        if(!result.assetSubItemInstance)
-            return fail(code:"default.not.found")
+            result.assetSubItemInstance = AssetSubItem.get(params.id)
 
-        if(result.assetSubItemInstance.assets)
-            return fail(code:"assetSubItem.assets.associated")
+            if(!result.assetSubItemInstance)
+                return fail(code:"default.not.found")
 
-        if(result.assetSubItemInstance.maintenanceActions)
-            return fail(code:"maintenanceActions.still.associated")
+            for(subItem in result.assetSubItemInstance.subItems) {
+                if(subItem.maintenanceActions)
+                    fail(code:"maintenanceActions.still.associated.subItem")
+            }
 
-        try {
-            result.assetSubItemInstance.delete(flush:true)
+            if(result.error)
+                return result
+
+            if(result.assetSubItemInstance.maintenanceActions)
+                return fail(code:"maintenanceActions.still.associated")
+
+            if(result.assetSubItemInstance.assets)
+                return fail(code:"assetSubItem.assets.associated")
+
+            // We have handled all the foreign keys so the delete should go forward.
+            // Can't flush here due to cascading from Section and Site.
+            // And without flush there is no point it trying to catch the dao.DataIntegrityViolationException
+            // since that will only happen after leaving the transaction.
+            result.assetSubItemInstance.delete()
             return result //Success.
-        }
-        catch(org.springframework.dao.DataIntegrityViolationException e) {
-            return fail(code:"default.delete.failure")
-        }
 
+        } // withTransaction
     }
 
Index: trunk/grails-app/services/SectionService.groovy
===================================================================
--- trunk/grails-app/services/SectionService.groovy	(revision 360)
+++ trunk/grails-app/services/SectionService.groovy	(revision 360)
@@ -0,0 +1,55 @@
+class SectionService {
+
+    boolean transactional = false
+
+    def assetSubItemService
+    def assetService
+
+    def delete(params) {
+        Section.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.sectionInstance && m.field)
+                    result.sectionInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Section", params.id] ]
+                return result
+            }
+
+            result.sectionInstance = Section.get(params.id)
+
+            if(!result.sectionInstance)
+                return fail(code:"default.not.found")
+
+            if(result.sectionInstance.maintenanceActions)
+                return fail(code:"maintenanceActions.still.associated")
+
+            // Delete assets which in turn delete orphan assetSubItems.
+            def assets = new ArrayList(result.sectionInstance.assets) // avoid ConcurrentModificationException.
+            def r
+            for(asset in assets) {
+                result.sectionInstance.removeFromAssets(asset)
+                r = assetService.delete(id: asset.id)
+                if(r.error) {
+                    log.debug r.error
+                    fail(code:"section.asset.delete.failure")
+                    break
+                }
+            }
+
+            if(result.error)
+                return result
+
+            try {
+                result.sectionInstance.delete(flush:true)
+                return result //Success.
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                return fail(code:"default.delete.failure")
+            }
+
+        } // end withTransaction
+    } // end delete()
+
+} // end class
Index: trunk/grails-app/services/SiteService.groovy
===================================================================
--- trunk/grails-app/services/SiteService.groovy	(revision 360)
+++ trunk/grails-app/services/SiteService.groovy	(revision 360)
@@ -0,0 +1,54 @@
+class SiteService {
+
+    boolean transactional = false
+
+    def sectionService
+
+    def delete(params) {
+        Site.withTransaction { status ->
+            def result = [:]
+
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.siteInstance && m.field)
+                    result.siteInstance.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["Site", params.id] ]
+                return result
+            }
+
+            result.siteInstance = Site.get(params.id)
+
+            if(!result.siteInstance)
+                return fail(code:"default.not.found")
+
+            if(result.siteInstance.inventoryStores)
+                return fail(code:"inventoryStores.still.associated")
+
+            // Delete sections which in turn deletes assets etc.
+            def sections = new ArrayList(result.siteInstance.sections) // avoid ConcurrentModificationException.
+            def r
+            for(section in sections) {
+                result.siteInstance.removeFromSections(section)
+                r = sectionService.delete(id: section.id)
+                if(r.error) {
+                    log.debug r.error
+                    fail(code:"site.section.delete.failure")
+                    break
+                }
+            }
+
+            if(result.error)
+                return result
+
+            try {
+                result.siteInstance.delete(flush:true)
+                return result //Success.
+            }
+            catch(org.springframework.dao.DataIntegrityViolationException e) {
+                return fail(code:"default.delete.failure")
+            }
+
+        } // end withTransaction
+    } // end delete()
+
+} // end class
