diff --git a/grails-app/services/au/org/ala/ecodata/MetadataService.groovy b/grails-app/services/au/org/ala/ecodata/MetadataService.groovy index 3e0f71f4c..9e9d4441b 100644 --- a/grails-app/services/au/org/ala/ecodata/MetadataService.groovy +++ b/grails-app/services/au/org/ala/ecodata/MetadataService.groovy @@ -514,8 +514,8 @@ class MetadataService { * uses the supplied field id. * @param fid the field id. */ - Map getGeographicFacetConfig(String fid) { - Map config = getGeographicConfig() + Map getGeographicFacetConfig(String fid, String hubId = null) { + Map config = getGeographicConfig(hubId) Map facetConfig = null config.contextual.each { String groupName, String groupFid -> if (fid == groupFid) { diff --git a/grails-app/services/au/org/ala/ecodata/ProjectService.groovy b/grails-app/services/au/org/ala/ecodata/ProjectService.groovy index e8ae88d73..71afced38 100644 --- a/grails-app/services/au/org/ala/ecodata/ProjectService.groovy +++ b/grails-app/services/au/org/ala/ecodata/ProjectService.groovy @@ -1158,13 +1158,14 @@ class ProjectService { Map orderLayerIntersectionsByAreaOfProjectSites (Map project) { Map> sumOfIntersectionsByLayer = [:].withDefault { [:].withDefault { 0 } } Map orderedIntersectionsByArea = [:] - // get sites of projects; + Map config = metadataService.getGeographicConfig(project.hubId) + List layers = config.checkForBoundaryIntersectionInLayers List projectSites = getRepresentativeSitesOfProject(project) projectSites?.each { Map site -> - site.extent?.geometry?.get(SpatialService.INTERSECTION_AREA)?.each { String layerId, Map value -> - Set keySet = value.keySet() - keySet.each { String layerValue -> - sumOfIntersectionsByLayer[layerId][layerValue] += value[layerValue] + layers.each { String layer -> + Map facet = metadataService.getGeographicFacetConfig(layer, project.hubId) + site.extent?.geometry?.get(SpatialService.INTERSECTION_AREA)?.get(facet.name)?.get(SiteService.INTERSECTION_CURRENT)?.each { String layerValue, value -> + sumOfIntersectionsByLayer[layer][layerValue] += value } } } diff --git a/grails-app/services/au/org/ala/ecodata/SiteService.groovy b/grails-app/services/au/org/ala/ecodata/SiteService.groovy index ee12276f6..2e48008f5 100644 --- a/grails-app/services/au/org/ala/ecodata/SiteService.groovy +++ b/grails-app/services/au/org/ala/ecodata/SiteService.groovy @@ -28,6 +28,7 @@ class SiteService { static final PLANNING_SITE = 'Planning site' static final EMSA_SITE = 'EMSA site' static final REPORTING_SITE = 'Reporting site' + static final INTERSECTION_CURRENT = 'CURRENT' def grailsApplication, activityService, projectService, commonService, webService, documentService, metadataService, cacheService PermissionService permissionService @@ -663,10 +664,37 @@ class SiteService { log.error("No geometry for site: ${site.siteId}") } - site.extent.geometry += lookupGeographicFacetsForSite(site, fids) + def geoFacets = lookupGeographicFacetsForSite(site, fids) + def intersectionsAreaByFacets = geoFacets.remove(SpatialService.INTERSECTION_AREA) + site.extent.geometry += geoFacets + mergeIntersectionsArea(site, intersectionsAreaByFacets) } } + /** + * The data is stored in the format - + * [ intersectionAreaByFacets: [ CURRENT: [act: 0.1, nsw: 0.6], cl22: [act: 0.1, nsw: 0.6]] ] + * @param site + * @param intersectionsAreaByFacets + * @return + */ + def mergeIntersectionsArea(Map site, Map intersectionsAreaByFacets) { + Map geometry = site.extent.geometry + List hubs = projectService.findHubIdOfProjects(site.projects) + String hubId = hubs?.size() == 1 ? hubs[0] : null + Map existingIntersectionsArea = geometry[SpatialService.INTERSECTION_AREA] = geometry[SpatialService.INTERSECTION_AREA] ?: [:] + intersectionsAreaByFacets?.each { String layer, Map nameAndValue -> + if (nameAndValue) { + Map facet = metadataService.getGeographicFacetConfig(layer, hubId) + existingIntersectionsArea[facet.name] = existingIntersectionsArea[facet.name]?: [:] + existingIntersectionsArea[facet.name][INTERSECTION_CURRENT] = nameAndValue + existingIntersectionsArea[facet.name][layer] = nameAndValue + } + } + + site + } + /** * get images for a list of sites. The images are associated with the point of interest of each site. * @param ids diff --git a/src/test/groovy/au/org/ala/ecodata/ProjectServiceSpec.groovy b/src/test/groovy/au/org/ala/ecodata/ProjectServiceSpec.groovy index e4c73885d..17d03e683 100644 --- a/src/test/groovy/au/org/ala/ecodata/ProjectServiceSpec.groovy +++ b/src/test/groovy/au/org/ala/ecodata/ProjectServiceSpec.groovy @@ -44,6 +44,13 @@ class ProjectServiceSpec extends MongoSpec implements ServiceUnitTest> [ + contextual: [ + elect : 'cl11163' + ], + "checkForBoundaryIntersectionInLayers" : [ "cl11163" ] + ] + metadataService.getGeographicFacetConfig("cl11163", "12345") >> [name: "elect", grouped: true] + Project.withSession { session -> + project1 = new Project(projectId: '111', name: "Project 111", hubId:"12345", isMERIT: true).save(flush: true, failOnError: true) + Site site1 = new Site(siteId: 's1', name: "Site 1", type: "compound", projects: ['111'], extent: [ source: "point", geometry: [intersectionAreaByFacets: ["elect": ["CURRENT": ["bean": 0.1, "canberra": 0.2, "fenner": 0.25]]]]]).save(flush: true) + Site site2 = new Site(siteId: 's2', name: "Site 2", type: "compound", projects: ['111'], extent: [ source: "point", geometry: [intersectionAreaByFacets: ["elect": ["CURRENT": ["bean": 0.7, "canberra": 0.4, "fenner": 0.5]]]]]).save(flush: true) + project1.metaClass.getDbo = { new BasicDBObject(project1.properties) } + session.flush() + projectMap = service.toMap(project1, ProjectService.ALL) + } when: - Map result = service.orderLayerIntersectionsByAreaOfProjectSites(projectMap) + Project.withSession { + result = service.orderLayerIntersectionsByAreaOfProjectSites(projectMap) + } then: result.size() == 1 - result."cl11163"[0] == "bean" - result."cl11163"[1] == "fenner" - result."cl11163"[2] == "canberra" + result["cl11163"][0] == "bean" + result["cl11163"][1] == "fenner" + result["cl11163"][2] == "canberra" } void "getRepresentativeSitesOfProject should get EMSA site or Reporting sites only" () { setup: - ManagementUnit mu = new ManagementUnit(managementUnitId: 'mu1', name: "Management Unit 1", managementUnitSiteId: 's4').save() - Project project1 = new Project(projectId: '111', name: "Project 111", hubId:"12345", isMERIT: true, managementUnitId: 'mu1') - project1.save(flush: true) - Site site1 = new Site(siteId: 's1', name: "Site 1", type: "compound", projects: ['111'], extent: [ source: "point", geometry: [intersectionAreaByFacets: ["cl11163": ["bean": 0.1, "canberra": 0.2, "fenner": 0.25]]]]).save(flush: true) - Site site2 = new Site(siteId: 's2', name: "Site 2", type: "compound", projects: ['111'], extent: [ source: "point", geometry: [intersectionAreaByFacets: ["cl11163": ["bean": 0.7, "canberra": 0.4, "fenner": 0.5]]]]).save(flush: true) - Site site3 = new Site(siteId: 's3', name: "Site 3", externalIds: [[idType: ExternalId.IdType.MONITOR_PROTOCOL_INTERNAL_ID, externalId: '1']], projects: ['111'], extent: [ source: "point", geometry: [intersectionAreaByFacets: ["cl11163": ["bean": 0.0, "canberra": 0.1, "fenner": 0.6]]]]).save(flush: true) - Site site4 = new Site(siteId: 's4', name: "Site 4", type: "worksArea", extent: [ source: "point", geometry: [intersectionAreaByFacets: ["cl11163": ["bean": 0.7, "canberra": 0.4, "fenner": 0.5]]]]).save(flush: true) - Site site5 = new Site(siteId: 's5', name: "Site 5", type: "worksArea", projects: ['111'], extent: [ source: "point", geometry: [intersectionAreaByFacets: ["cl11163": ["bean": 0.7, "canberra": 0.4, "fenner": 0.5]]]]).save(flush: true) - project1.metaClass.getDbo = { new BasicDBObject(project1.properties) } Map projectMap - projectMap = service.toMap(project1, ProjectService.ALL) + Site site1, site2, site3, site4, site5 + Project project1 + ManagementUnit mu + List result + Project.withSession { session -> + project1 = new Project(projectId: '111', name: "Project 111", hubId:"12345", isMERIT: true, managementUnitId: 'mu1').save(flush: true) + mu = new ManagementUnit(managementUnitId: 'mu1', name: "Management Unit 1", managementUnitSiteId: 's4').save(flush: true) + site1 = new Site(siteId: 's1', name: "Site 1", type: "compound", projects: ['111'], extent: [ source: "point", geometry: [intersectionAreaByFacets: ["cl11163": ["bean": 0.1, "canberra": 0.2, "fenner": 0.25]]]]).save(flush: true) + site2 = new Site(siteId: 's2', name: "Site 2", type: "compound", projects: ['111'], extent: [ source: "point", geometry: [intersectionAreaByFacets: ["cl11163": ["bean": 0.7, "canberra": 0.4, "fenner": 0.5]]]]).save(flush: true) + site3 = new Site(siteId: 's3', name: "Site 3", externalIds: [[idType: ExternalId.IdType.MONITOR_PROTOCOL_INTERNAL_ID, externalId: '1']], projects: ['111'], extent: [ source: "point", geometry: [intersectionAreaByFacets: ["cl11163": ["bean": 0.0, "canberra": 0.1, "fenner": 0.6]]]]).save(flush: true) + site4 = new Site(siteId: 's4', name: "Site 4", type: "worksArea", extent: [ source: "point", geometry: [intersectionAreaByFacets: ["cl11163": ["bean": 0.7, "canberra": 0.4, "fenner": 0.5]]]]).save(flush: true) + site5 = new Site(siteId: 's5', name: "Site 5", type: "worksArea", projects: ['111'], extent: [ source: "point", geometry: [intersectionAreaByFacets: ["cl11163": ["bean": 0.7, "canberra": 0.4, "fenner": 0.5]]]]).save(flush: true) + project1.metaClass.getDbo = { new BasicDBObject(project1.properties) } + session.flush() + projectMap = service.toMap(project1, ProjectService.ALL) + } when: // returns reporting and EMSA sites Only - List result = service.getRepresentativeSitesOfProject(projectMap) + Project.withSession { + result = service.getRepresentativeSitesOfProject(projectMap) + } then: result.size() == 3 @@ -960,13 +990,17 @@ class ProjectServiceSpec extends MongoSpec implements ServiceUnitTest + site1.type = Site.TYPE_PROJECT_AREA + site1.save(flush: true) + site2.type = Site.TYPE_WORKS_AREA + site2.save(flush: true) + site3.delete(flush: true) + project1.metaClass.getDbo = { new BasicDBObject(project1.properties) } + session.flush() + projectMap = service.toMap(project1, ProjectService.ALL) + result = service.getRepresentativeSitesOfProject(projectMap) + } then: result.size() == 3 @@ -975,22 +1009,30 @@ class ProjectServiceSpec extends MongoSpec implements ServiceUnitTest + site1.projects = site2.projects = site5.projects = [] + site1.save(flush: true) + site2.save(flush: true) + site5.save(flush: true) + project1.metaClass.getDbo = { new BasicDBObject(project1.properties) } + session.flush() + projectMap = service.toMap(project1, ProjectService.ALL) + result = service.getRepresentativeSitesOfProject(projectMap) + } then: result.size() == 1 result.siteId[0] == 's4' when:// returns empty - project1.managementUnitId = null - project1.save() - projectMap = service.toMap(project1, ProjectService.ALL) - result = service.getRepresentativeSitesOfProject(projectMap) + Project.withSession { session -> + project1.managementUnitId = null + project1.save(flush: true) + project1.metaClass.getDbo = { new BasicDBObject(project1.properties) } + session.flush() + projectMap = service.toMap(project1, ProjectService.ALL) + result = service.getRepresentativeSitesOfProject(projectMap) + } then: result.isEmpty() diff --git a/src/test/groovy/au/org/ala/ecodata/SiteServiceSpec.groovy b/src/test/groovy/au/org/ala/ecodata/SiteServiceSpec.groovy index c462a3295..b7b1b485f 100644 --- a/src/test/groovy/au/org/ala/ecodata/SiteServiceSpec.groovy +++ b/src/test/groovy/au/org/ala/ecodata/SiteServiceSpec.groovy @@ -20,6 +20,7 @@ class SiteServiceSpec extends MongoSpec implements ServiceUnitTest def webServiceMock = Mock(WebService) def metadataServiceMock = Mock(MetadataService) def spatialServiceMock = Mock(SpatialService) + def projectService = Mock(ProjectService) CommonService commonService = new CommonService() void setup() { //defineBeans { @@ -35,6 +36,7 @@ class SiteServiceSpec extends MongoSpec implements ServiceUnitTest service.grailsApplication = grailsApplication service.metadataService = metadataServiceMock service.spatialService = spatialServiceMock + service.projectService = projectService // grailsApplication.mainContext.registerSingleton('commonService', CommonService) // grailsApplication.mainContext.commonService.grailsApplication = grailsApplication } @@ -192,6 +194,7 @@ class SiteServiceSpec extends MongoSpec implements ServiceUnitTest def "New sites without a centroid should have one assigned"() { when: def result + projectService.findHubIdOfProjects(_) >> [] Site.withSession { session -> result = service.create([name: 'Site 1', extent: [source: 'pid', geometry: [type: 'pid', pid: 'cl123']]]) session.flush() @@ -307,6 +310,7 @@ class SiteServiceSpec extends MongoSpec implements ServiceUnitTest def "The site area is calculated from the FeatureCollection for a compound site"() { setup: + projectService.findHubIdOfProjects(_) >> [] def coordinates = [[148.260498046875, -37.26530995561874], [148.260498046875, -37.26531995561874], [148.310693359375, -37.26531995561874], [148.310693359375, -37.26531995561874], [148.260498046875, -37.26530995561874]] def extent = buildExtent('drawn', 'Polygon', coordinates) Map site = [type: Site.TYPE_COMPOUND, extent: extent, features: [