Commit 7ecf39a9 authored by COTONNEC's avatar COTONNEC
Browse files

[enh] add gear and target specie filter on operation

[enh] add OperationFetchOptions
parent 5e1cb7f5
......@@ -24,19 +24,17 @@ package net.sumaris.core.dao.data.operation;
import net.sumaris.core.dao.data.DataRepository;
import net.sumaris.core.model.data.Operation;
import net.sumaris.core.vo.data.DataFetchOptions;
import net.sumaris.core.vo.data.OperationFetchOptions;
import net.sumaris.core.vo.data.OperationVO;
import net.sumaris.core.vo.filter.OperationFilterVO;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
/**
* @author peck7 on 01/09/2020.
*/
public interface OperationRepository
extends DataRepository<Operation, OperationVO, OperationFilterVO, DataFetchOptions>,
extends DataRepository<Operation, OperationVO, OperationFilterVO, OperationFetchOptions>,
OperationSpecifications {
@Query("select p.id from Operation o inner join o.trip t inner join t.program p where o.id = :id")
......
......@@ -30,6 +30,7 @@ import net.sumaris.core.dao.data.batch.BatchRepository;
import net.sumaris.core.dao.data.fishingArea.FishingAreaRepository;
import net.sumaris.core.dao.data.physicalGear.PhysicalGearRepository;
import net.sumaris.core.dao.data.sample.SampleRepository;
import net.sumaris.core.dao.data.trip.TripRepository;
import net.sumaris.core.dao.referential.metier.MetierRepository;
import net.sumaris.core.dao.technical.Daos;
import net.sumaris.core.model.data.Operation;
......@@ -40,6 +41,7 @@ import net.sumaris.core.model.referential.metier.Metier;
import net.sumaris.core.util.Beans;
import net.sumaris.core.util.Dates;
import net.sumaris.core.vo.data.DataFetchOptions;
import net.sumaris.core.vo.data.OperationFetchOptions;
import net.sumaris.core.vo.data.OperationVO;
import net.sumaris.core.vo.data.batch.BatchFetchOptions;
import net.sumaris.core.vo.data.sample.SampleFetchOptions;
......@@ -59,7 +61,7 @@ import java.util.stream.Collectors;
*/
@Slf4j
public class OperationRepositoryImpl
extends DataRepositoryImpl<Operation, OperationVO, OperationFilterVO, DataFetchOptions>
extends DataRepositoryImpl<Operation, OperationVO, OperationFilterVO, OperationFetchOptions>
implements OperationSpecifications {
@Autowired
......@@ -80,21 +82,31 @@ public class OperationRepositoryImpl
@Autowired
private BatchRepository batchRepository;
@Autowired
private TripRepository tripRepository;
@Autowired
protected VesselPositionDao vesselPositionDao;
protected OperationRepositoryImpl(EntityManager entityManager) {
super(Operation.class, OperationVO.class, entityManager);
setLockForUpdate(true);
}
@Override
public void toVO(Operation source, OperationVO target, DataFetchOptions fetchOptions, boolean copyIfNull) {
public void toVO(Operation source, OperationVO target, OperationFetchOptions fetchOptions, boolean copyIfNull) {
super.toVO(source, target, fetchOptions, copyIfNull);
// Trip
if (source.getTrip() != null) {
target.setTripId(source.getTrip().getId());
if (fetchOptions != null && fetchOptions.isWithTrip()){
target.setTrip(tripRepository.toVO(source.getTrip(), DataFetchOptions.builder()
.withRecorderDepartment(false)
.withRecorderPerson(false)
.build()));
}
}
// Physical gear
......@@ -147,15 +159,26 @@ public class OperationRepositoryImpl
// ParentOperation
if (source.getParentOperation() != null) {
target.setParentOperationId(source.getParentOperation().getId());
target.setParentOperation(this.findById(target.getParentOperationId(), fetchOptions).orElse(null));
if (fetchOptions == null || fetchOptions.isWithLinkedOperation()) {
if (fetchOptions == null) {
fetchOptions = OperationFetchOptions.builder().build();
}
fetchOptions.setWithLinkedOperation(false);
target.setParentOperation(this.findById(target.getParentOperationId(), fetchOptions).orElse(null));
}
}
// ChildOperation
if (fetchOptions != null && fetchOptions.isWithChildrenEntities() && target.getParentOperation() == null && source.getChildOperation() != null) {
if (target.getParentOperation() == null && source.getChildOperation() != null) {
target.setChildOperationId(source.getChildOperation().getId());
target.setChildOperation(this.findById(target.getChildOperationId(), fetchOptions).orElse(null));
if (fetchOptions == null || fetchOptions.isWithLinkedOperation()) {
if (fetchOptions == null) {
fetchOptions = OperationFetchOptions.builder().build();
}
fetchOptions.setWithLinkedOperation(false);
target.setChildOperation(this.findById(target.getChildOperationId(), fetchOptions).orElse(null));
}
}
}
@Override
......@@ -269,17 +292,16 @@ public class OperationRepositoryImpl
}
//Quality Flag
Integer qualityFlag = source.getQualityFlagId() ;
if (qualityFlag != null){
Integer qualityFlag = source.getQualityFlagId();
if (qualityFlag != null) {
target.setQualityFlag(getReference(QualityFlag.class, qualityFlag));
}
else {
} else {
target.setQualityFlag(getReference(QualityFlag.class, getConfig().getDefaultQualityFlagId()));
}
}
@Override
protected Specification<Operation> toSpecification(OperationFilterVO filter, DataFetchOptions fetchOptions) {
protected Specification<Operation> toSpecification(OperationFilterVO filter, OperationFetchOptions fetchOptions) {
return super.toSpecification(filter, fetchOptions)
.and(hasTripId(filter.getTripId()))
.and(hasProgramLabel(filter.getProgramLabel()))
......@@ -288,6 +310,9 @@ public class OperationRepositoryImpl
.and(notChildOperation(filter.getExcludeChildOperation()))
.and(hasNoChildOperation(filter.getExcludeChildOperation()))
.and(isBetweenDates(filter.getStartDate(), filter.getEndDate()))
.and(inGearIds(filter.getGearIds()))
.and(inTaxonGroupLabels(filter.getTaxonGroupLabels()))
.and(hasQualityFlagId(filter.getQualityFlagId()))
.or(includedIds(filter.getIncludedIds()));
}
......@@ -295,7 +320,7 @@ public class OperationRepositoryImpl
protected void onAfterSaveEntity(OperationVO vo, Operation savedEntity, boolean isNew) {
super.onAfterSaveEntity(vo, savedEntity, isNew);
if (vo.getParentOperation() == null && vo.getParentOperationId() != null){
if (vo.getParentOperation() == null && vo.getParentOperationId() != null) {
vo.setParentOperation(this.get(vo.getParentOperationId()));
}
}
......
......@@ -26,8 +26,12 @@ import net.sumaris.core.dao.data.DataSpecifications;
import net.sumaris.core.dao.technical.jpa.BindableSpecification;
import net.sumaris.core.dao.technical.model.IEntity;
import net.sumaris.core.model.data.Operation;
import net.sumaris.core.model.data.PhysicalGear;
import net.sumaris.core.model.data.Trip;
import net.sumaris.core.model.referential.IItemReferentialEntity;
import net.sumaris.core.model.referential.QualityFlag;
import net.sumaris.core.model.referential.metier.Metier;
import net.sumaris.core.model.referential.taxon.TaxonGroup;
import net.sumaris.core.vo.data.OperationVO;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.data.jpa.domain.Specification;
......@@ -55,6 +59,9 @@ public interface OperationSpecifications
String HAS_NO_CHILD_OPERATION_PARAM = "hasNoChildOperation";
String START_DATE_PARAM = "startDate";
String END_DATE_PARAM = "endDate";
String GEAR_IDS_PARAMETER = "gearIds";
String TAXON_GROUP_LABELS_PARAMETER = "targetSpecieIds";
String QUALITY_FLAG_ID_PARAMETER = "qualityFlagId";
default Specification<Operation> hasTripId(Integer tripId) {
if (tripId == null) return null;
......@@ -146,6 +153,29 @@ public interface OperationSpecifications
return specification;
}
default Specification<Operation> inGearIds(Integer[] gearIds) {
if (ArrayUtils.isEmpty(gearIds)) return null;
return BindableSpecification.<Operation>where((root, query, criteriaBuilder) -> {
ParameterExpression<Collection> param = criteriaBuilder.parameter(Collection.class, GEAR_IDS_PARAMETER);
Join<Operation, PhysicalGear> physicalGearJoin = root.join(Operation.Fields.PHYSICAL_GEAR, JoinType.INNER);
return criteriaBuilder.in(physicalGearJoin.get(PhysicalGear.Fields.GEAR).get(IEntity.Fields.ID)).value(param);
})
.addBind(GEAR_IDS_PARAMETER, Arrays.asList(gearIds));
}
default Specification<Operation> inTaxonGroupLabels(String[] taxonGroupLabels) {
if (ArrayUtils.isEmpty(taxonGroupLabels)) return null;
return BindableSpecification.<Operation>where((root, query, criteriaBuilder) -> {
ParameterExpression<Collection> param = criteriaBuilder.parameter(Collection.class, TAXON_GROUP_LABELS_PARAMETER);
Join<Operation, Metier> metierJoin = root.join(Operation.Fields.METIER, JoinType.INNER);
return criteriaBuilder.in(metierJoin.get(Metier.Fields.TAXON_GROUP).get(TaxonGroup.Fields.LABEL)).value(param);
})
.addBind(TAXON_GROUP_LABELS_PARAMETER, Arrays.asList(taxonGroupLabels));
}
default Specification<Operation> isBetweenDates(Date startDate, Date endDate) {
BindableSpecification<Operation> specification = BindableSpecification.where((root, query, criteriaBuilder) -> {
......@@ -188,5 +218,18 @@ public interface OperationSpecifications
return specification;
}
default Specification<Operation> hasQualityFlagId(Integer qualityFlagId) {
if (qualityFlagId == null) return null;
BindableSpecification<Operation> specification = BindableSpecification.where((root, query, criteriaBuilder) -> {
ParameterExpression<Integer> param = criteriaBuilder.parameter(Integer.class, QUALITY_FLAG_ID_PARAMETER);
return criteriaBuilder.or(
criteriaBuilder.isNull(param),
criteriaBuilder.equal(root.get(Operation.Fields.QUALITY_FLAG).get(QualityFlag.Fields.ID), param)
);
});
specification.addBind(QUALITY_FLAG_ID_PARAMETER, qualityFlagId);
return specification;
}
List<OperationVO> saveAllByTripId(int tripId, List<OperationVO> operations);
}
package net.sumaris.core.model.data;
/*-
* #%L
* SUMARiS:: Core
* %%
* Copyright (C) 2018 SUMARiS Consortium
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import net.sumaris.core.dao.technical.model.IEntity;
import java.io.Serializable;
import java.util.List;
public interface IWithTripEntity<T extends Serializable, B extends IEntity<Integer>> extends IEntity<T> {
interface Fields extends IEntity.Fields {
String TRIP = "trip";
}
B getTrip();
void setTrip(B trip);
}
......@@ -24,7 +24,7 @@ package net.sumaris.core.service.data;
import net.sumaris.core.dao.technical.SortDirection;
import net.sumaris.core.vo.data.DataFetchOptions;
import net.sumaris.core.vo.data.OperationFetchOptions;
import net.sumaris.core.vo.data.OperationVO;
import net.sumaris.core.vo.filter.OperationFilterVO;
import org.springframework.transaction.annotation.Transactional;
......@@ -42,13 +42,13 @@ public interface OperationService {
@Transactional(readOnly = true)
List<OperationVO> findAllByTripId(int tripId, DataFetchOptions fetchOptions);
List<OperationVO> findAllByTripId(int tripId, OperationFetchOptions fetchOptions);
@Transactional(readOnly = true)
List<OperationVO> findAllByTripId(int tripId, int offset, int size, String sortAttribute, SortDirection sortDirection, DataFetchOptions fetchOptions);
List<OperationVO> findAllByTripId(int tripId, int offset, int size, String sortAttribute, SortDirection sortDirection, OperationFetchOptions fetchOptions);
@Transactional(readOnly = true)
List<OperationVO> findAllByFilter(OperationFilterVO filter, int offset, int size, String sortAttribute, SortDirection sortDirection, DataFetchOptions fetchOptions);
List<OperationVO> findAllByFilter(OperationFilterVO filter, int offset, int size, String sortAttribute, SortDirection sortDirection, OperationFetchOptions fetchOptions);
@Transactional(readOnly = true)
Long countByTripId(int tripId);
......
......@@ -91,14 +91,14 @@ public class OperationServiceImpl implements OperationService {
@Override
public List<OperationVO> findAllByTripId(int tripId, @NonNull DataFetchOptions fetchOptions) {
public List<OperationVO> findAllByTripId(int tripId, @NonNull OperationFetchOptions fetchOptions) {
return operationRepository.findAllVO(operationRepository.hasTripId(tripId), fetchOptions);
}
@Override
public List<OperationVO> findAllByTripId(int tripId,
int offset, int size, String sortAttribute, SortDirection sortDirection,
@NonNull DataFetchOptions fetchOptions) {
@NonNull OperationFetchOptions fetchOptions) {
return operationRepository.findAllVO(operationRepository.hasTripId(tripId),
Pageables.create(offset, size, sortAttribute, sortDirection),
fetchOptions).getContent();
......@@ -106,7 +106,7 @@ public class OperationServiceImpl implements OperationService {
@Override
public List<OperationVO> findAllByFilter(OperationFilterVO filter, int offset, int size, String sortAttribute, SortDirection sortDirection,
@NonNull DataFetchOptions fetchOptions) {
@NonNull OperationFetchOptions fetchOptions) {
return operationRepository.findAll(filter != null ? filter : OperationFilterVO.builder().build(), offset, size, sortAttribute, sortDirection, fetchOptions).getContent();
}
......
......@@ -152,7 +152,13 @@ public class TripServiceImpl implements TripService {
// Operations
else {
target.setOperations(operationService.findAllByTripId(id, fetchOptions));
OperationFetchOptions operationFetchOptions = OperationFetchOptions.builder()
.withObservers(fetchOptions.isWithObservers())
.withRecorderDepartment(fetchOptions.isWithRecorderDepartment())
.withRecorderPerson(fetchOptions.isWithRecorderPerson())
.build();
target.setOperations(operationService.findAllByTripId(id, operationFetchOptions));
}
}
......
......@@ -33,6 +33,7 @@ import net.sumaris.core.service.data.OperationService;
import net.sumaris.core.service.data.TripService;
import net.sumaris.core.util.TimeUtils;
import net.sumaris.core.vo.data.DataFetchOptions;
import net.sumaris.core.vo.data.OperationFetchOptions;
import net.sumaris.core.vo.data.OperationVO;
import net.sumaris.core.vo.data.TripVO;
import net.sumaris.core.vo.data.batch.DenormalizedBatchOptions;
......@@ -164,7 +165,7 @@ public class DenormalizeTripServiceImpl implements DenormalizeTripService {
List<OperationVO> operations = operationService.findAllByTripId(tripId,
offset, pageSize, // Page
OperationVO.Fields.ID, SortDirection.ASC, // Sort by id, to keep continuity between pages
DataFetchOptions.builder()
OperationFetchOptions.builder()
.withChildrenEntities(false)
.withMeasurementValues(false)
.build());
......
/*
* #%L
* SUMARiS
* %%
* Copyright (C) 2019 SUMARiS Consortium
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package net.sumaris.core.vo.data;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class OperationFetchOptions implements IDataFetchOptions {
public static final OperationFetchOptions DEFAULT = OperationFetchOptions.builder().build();
@Builder.Default
private boolean withRecorderDepartment = true;
@Builder.Default
private boolean withRecorderPerson = true;
@Builder.Default
private boolean withObservers = true;
@Builder.Default
private boolean withChildrenEntities = false;
@Builder.Default
private boolean withMeasurementValues = false;
@Builder.Default
private boolean withLinkedOperation = true;
@Builder.Default
private boolean withTrip = false;
}
......@@ -51,5 +51,9 @@ public class OperationFilterVO implements IDataFilter {
private Boolean hasNoChildOperation;
private Date startDate;
private Date endDate;
private Integer[] gearIds;
private String[] taxonGroupLabels;
private Integer qualityFlagId;
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
~ #%L
~ SUMARiS
~ %%
~ Copyright (C) 2019 SUMARiS Consortium
~ %%
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as
~ published by the Free Software Foundation, either version 3 of the
~ License, or (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public
~ License along with this program. If not, see
~ <http://www.gnu.org/licenses/gpl-3.0.html>.
~ #L%
-->
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd"
logicalFilePath="https://github.com/sumaris-net/sumaris-pod/blob/master/sumaris-core/src/main/resources/net/sumaris/core/db/changelog/hsqldb/acost/db-changelog-1.10.3.xml">
<property name="sqlCheck.empty.sql" value="SELECT count(*) FROM STATUS"/>
<property name="sqlCheck.acost.sql" value="SELECT COUNT(*) FROM PROGRAM WHERE LABEL = 'ACOST'"/>
<property name="sqlCheck.acost.expectedResult" value="1"/>
<preConditions onFail="WARN" onFailMessage="Database instance is not a ACOST database instance ! Do not include this changelog file in the master file">
<or>
<!-- Test if database is empty -->
<sqlCheck expectedResult="0">${sqlCheck.empty.sql}</sqlCheck>
<!-- OR if expected production database -->
<sqlCheck expectedResult="${sqlCheck.acost.expectedResult}">${sqlCheck.acost.sql}</sqlCheck>
</or>
</preConditions>
<!-- Add PMFM HAS_INDIVIDUAL_MEASUREMENT -->
<changeSet author="camille.cotonnec@e-is.pro" id="1625816880597-301" runOnChange="true">
<preConditions onFail="MARK_RAN">
<and>
<sqlCheck expectedResult="${sqlCheck.acost.expectedResult}">${sqlCheck.acost.sql}</sqlCheck>
<sqlCheck expectedResult="0">SELECT COUNT(ID) FROM PMFM WHERE LABEL='HAS_INDIVIDUAL_MEASUREMENT' AND ID=381</sqlCheck>
</and>
</preConditions>
<sql><![CDATA[
insert into PMFM (id, parameter_fk, label, unit_fk, creation_date, update_date)
values (381, 121, 'HAS_INDIVIDUAL_MEASUREMENT', 0, 1, '2021-09-01', '2021-09-01');
]]>
</sql>
</changeSet>
</databaseChangeLog>
......@@ -106,6 +106,7 @@
<include relativeToChangelogFile="true" file="all/db-changelog-1.10.0.xml"/>
<include relativeToChangelogFile="true" file="db-changelog-1.10.3.xml"/>
<include relativeToChangelogFile="true" file="acost/db-changelog-1.10.3.xml"/>
<!-- Refresh schema objects (functions, procedures, triggers, ...) -->
<include relativeToChangelogFile="true" file="db-changelog-refresh.xml"/>
......
......@@ -19,5 +19,6 @@
<include relativeToChangelogFile="true" file="db-changelog-1.10.0.xml"/>
<include relativeToChangelogFile="true" file="db-changelog-1.10.3.xml"/>
<include relativeToChangelogFile="true" file="acost/db-changelog-1.10.3.xml"/>
</databaseChangeLog>
......@@ -77,7 +77,7 @@ public class OperationServiceWriteTest extends AbstractServiceTest {
@Test
public void b_getAll() {
List<OperationVO> operations = service.findAllByTripId(parent.getId(), DataFetchOptions.DEFAULT);
List<OperationVO> operations = service.findAllByTripId(parent.getId(), OperationFetchOptions.DEFAULT);
Assert.assertNotNull(operations);
Assert.assertEquals(3, operations.size());
......
......@@ -94,7 +94,7 @@ public class TripServiceWriteTest extends AbstractServiceTest{
Assert.assertNotNull(savedVO.getId());
// Reload and check
List<OperationVO> savedOperations = operationService.findAllByTripId(savedVO.getId(), DataFetchOptions.DEFAULT);
List<OperationVO> savedOperations = operationService.findAllByTripId(savedVO.getId(), OperationFetchOptions.DEFAULT);
Assert.assertNotNull(savedOperations);
Assert.assertEquals(1, savedOperations.size());
......
......@@ -732,7 +732,7 @@ public class DataGraphQLService {
Preconditions.checkNotNull(filter.getTripId(), "Missing filter or filter.tripId");
return operationService.findAllByTripId(filter.getTripId(), offset, size, sort,
SortDirection.fromString(direction),
DataFetchOptions.DEFAULT);
OperationFetchOptions.DEFAULT);
}
@GraphQLQuery(name = "operations", description = "Get trip's operations")
......@@ -740,7 +740,7 @@ public class DataGraphQLService {
if (CollectionUtils.isNotEmpty(trip.getOperations())) {
return trip.getOperations();
}
return operationService.findAllByTripId(trip.getId(), DataFetchOptions.DEFAULT);
return operationService.findAllByTripId(trip.getId(), OperationFetchOptions.DEFAULT);
}
@GraphQLQuery(name = "operations", description = "Search in operations")
......@@ -764,7 +764,7 @@ public class DataGraphQLService {
return operationService.findAllByFilter(filter,
offset, size, sort, sortDirection,
getFetchOptions(fields));
getOperationFetchOptions(fields));
}
@GraphQLQuery(name = "operationsCount", description = "Get operations count")
......@@ -1473,6 +1473,16 @@ public class DataGraphQLService {
.build();
}
protected OperationFetchOptions getOperationFetchOptions(Set<String> fields) {
return OperationFetchOptions.builder()
.withObservers(fields.contains(StringUtils.slashing(IWithObserversEntity.Fields.OBSERVERS, IEntity.Fields.ID)))
.withRecorderDepartment(fields.contains(StringUtils.slashing(IWithRecorderDepartmentEntity.Fields.RECORDER_DEPARTMENT, IEntity.Fields.ID)))
.withRecorderPerson(fields.contains(StringUtils.slashing(IWithRecorderPersonEntity.Fields.RECORDER_PERSON, IEntity.Fields.ID)))
.withTrip(fields.contains(StringUtils.slashing(IWithTripEntity.Fields.TRIP, IEntity.Fields.ID)))
.build();
}
/**
* Restrict to self data and/or department data
* @param filter
......
......@@ -34,13 +34,11 @@ import net.sumaris.core.service.referential.ReferentialService;
import net.sumaris.core.service.referential.taxon.TaxonGroupService;
import net.sumaris.core.service.referential.taxon.TaxonNameService;
import net.sumaris.core.vo.data.TripVO;
import net.sumaris.core.vo.filter.IReferentialFilter;
import net.sumaris.core.vo.filter.MetierFilterVO;
import net.sumaris.core.vo.filter.ReferentialFilterVO;
import net.sumaris.core.vo.filter.TaxonNameFilterVO;
import net.sumaris.core.vo.referential.MetierVO;
import net.sumaris.core.vo.referential.ReferentialTypeVO;