Commit a53c5505 authored by Maxym Borodenko's avatar Maxym Borodenko
Browse files

Merge branch 'issue-with-updating-viability-data' into 'main'

Viability: ensure counterCooperator is returned

See merge request grin-global/grin-global-server!252
parents 14c439e0 f1cc6613
......@@ -101,7 +101,7 @@ public abstract class CRUDController<T extends EmptyModel, S extends CRUDService
@PutMapping(value = "", produces = { MediaType.APPLICATION_JSON_VALUE })
@Operation(operationId = "update", description = "Update an existing record", summary = "Update")
public T update(@RequestBody @Valid @NotNull final T entity) {
return crudService.update(entity, crudService.reload(entity));
return crudService.reload(crudService.update(entity));
}
}
\ No newline at end of file
......@@ -49,6 +49,7 @@ import org.gringlobal.custom.elasticsearch.SearchField;
import org.gringlobal.custom.validation.javax.CodeValueField;
import org.gringlobal.custom.validation.javax.OneLine;
import org.gringlobal.model.community.IWebVisible;
import org.hibernate.Hibernate;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
......@@ -66,6 +67,7 @@ import com.fasterxml.jackson.annotation.ObjectIdGenerators;
@BoostedFields({ "accessionNumber", "accessionNumberPart2", "taxonomySpecies.name", "names.plantName", "accessionSources.geography.countryCode" })
@JsonIdentityInfo(scope = Accession.class, generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Accession extends CooperatorOwnedModel implements IWebVisible, Copyable<Accession>, ElasticLoader, ElasticTrigger {
private static final long serialVersionUID = -6016814457794861535L;
@Id
@JsonProperty
......@@ -471,6 +473,8 @@ public class Accession extends CooperatorOwnedModel implements IWebVisible, Copy
if (this.taxonomySpecies != null) {
this.taxonomySpecies.getId();
}
Hibernate.initialize(this.backupLocation1Site);
Hibernate.initialize(this.backupLocation2Site);
}
@Override
......
......@@ -29,6 +29,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.gringlobal.model.community.CommunityCodeValues;
import org.gringlobal.model.community.IWebVisible;
import org.hibernate.Hibernate;
/**
* Auto-generated by:
......@@ -170,6 +171,7 @@ public class AccessionInvName extends CooperatorOwnedModel implements IWebVisibl
@Override
public Object[] reindexedEntities() {
Hibernate.initialize(this.inventory); // assures maybeReindex will work
return new Object[] { this.inventory };
}
}
\ No newline at end of file
......@@ -34,7 +34,9 @@ import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.Min;
import org.genesys.blocks.annotations.NotCopyable;
import org.genesys.blocks.model.Copyable;
import org.hibernate.Hibernate;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
......@@ -64,12 +66,14 @@ public class InventoryViabilityData extends CooperatorOwnedModel implements Copy
@JoinColumn(name = "inventory_viability_id", nullable = false, updatable = false)
@JsonIdentityReference(alwaysAsId = true)
@JsonIdentityInfo(scope = InventoryViability.class, generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@NotCopyable
private InventoryViability inventoryViability;
@ManyToOne(fetch = FetchType.LAZY, cascade = {})
@JoinColumn(name = "order_request_item_id", updatable = false)
@JsonIdentityReference(alwaysAsId = true)
@JsonIdentityInfo(scope = OrderRequestItem.class, generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@NotCopyable
private OrderRequestItem orderRequestItem;
@OneToMany(fetch = FetchType.LAZY, cascade = {}, mappedBy = "inventoryViabilityData")
......@@ -386,8 +390,9 @@ public class InventoryViabilityData extends CooperatorOwnedModel implements Copy
@Override
public void lazyLoad() {
Hibernate.initialize(this.inventoryViability);
if (this.counterCooperator != null) {
this.counterCooperator.getId();
Hibernate.initialize(this.counterCooperator);
}
if (dataEnvironmentMaps != null) {
dataEnvironmentMaps.size();
......
......@@ -25,6 +25,7 @@ import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.genesys.blocks.model.Copyable;
import org.gringlobal.custom.validation.javax.CodeValueField;
import org.gringlobal.custom.validation.javax.OneLine;
import org.hibernate.Hibernate;
/**
* Auto-generated by:
......@@ -207,4 +208,10 @@ public class Method extends CooperatorOwnedModel implements Copyable<Method> {
public void setUncertainty(final Integer uncertainty) {
this.uncertainty = uncertainty;
}
}
\ No newline at end of file
@Override
public void lazyLoad() {
super.lazyLoad();
Hibernate.initialize(this.geography);
}
}
......@@ -225,24 +225,23 @@ public class InventoryViabilityServiceImpl extends FilteredCRUDServiceImpl<Inven
@Transactional
@PostAuthorize("@ggceSec.actionAllowed('ViabilityTest', 'CREATE', returnObject.inventory.site)")
public InventoryViability create(InventoryViability source) {
InventoryViability inventoryViability = new InventoryViability();
inventoryViability.apply(source);
inventoryViability.setInventory(inventoryRepository.getOne(inventoryViability.getInventory().getId()));
assert(source.getId() == null);
source.setInventory(inventoryRepository.getOne(source.getInventory().getId()));
var rule = source.getInventoryViabilityRule();
if (rule != null) {
int numberOfReplicates = Optional.ofNullable(rule.getNumberOfReplicates()).orElse(1);
Integer testQuantity = rule.getSeedsPerReplicate() == null ? null : (int) rule.getSeedsPerReplicate() * numberOfReplicates;
inventoryViability.setReplicationCount(numberOfReplicates);
inventoryViability.setTotalTestedCount(testQuantity);
source.setReplicationCount(numberOfReplicates);
source.setTotalTestedCount(testQuantity);
}
if (inventoryViability.getTestedDate() == null) {
inventoryViability.setTestedDate(new Date());
if (source.getTestedDate() == null) {
source.setTestedDate(new Date());
}
inventoryViability.setTestedDateCode(CommunityCodeValues.DATE_FORMAT_DATE.value);
source.setTestedDateCode(CommunityCodeValues.DATE_FORMAT_DATE.value);
var saved = repository.save(inventoryViability);
var saved = repository.save(source);
saved.lazyLoad();
return saved;
......@@ -355,11 +354,10 @@ public class InventoryViabilityServiceImpl extends FilteredCRUDServiceImpl<Inven
@Transactional
@PostAuthorize("@ggceSec.actionAllowed('ViabilityTest', 'WRITE', returnObject.inventoryViability.inventory.site)")
public InventoryViabilityData create(InventoryViabilityData source) {
var created = new InventoryViabilityData();
created.apply(source);
// reload from database
created.setInventoryViability(inventoryViabilityRepository.getOne(created.getInventoryViability().getId()));
var saved = repository.save(created);
assert(source.getId() == null);
// reload from database: for post-authorize
source.setInventoryViability(inventoryViabilityRepository.getOne(source.getInventoryViability().getId()));
var saved = repository.save(source);
// Validate sum counts
validateSumOfCounts(saved);
......
......@@ -18,6 +18,7 @@ package org.gringlobal.service.triggers;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import org.apache.commons.collections4.IterableUtils;
......@@ -25,6 +26,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
......@@ -101,14 +103,22 @@ public class AccessionTriggers implements InitializingBean {
accessionClassPk = classPKService.getClassPk(Accession.class);
}
@Before(value = "execution(* org.genesys.blocks.auditlog.persistence.AuditLogRepository.saveAll(Iterable)) && args(auditLogs)")
public void beforeSaveAuditLogs(final JoinPoint joinPoint, final Collection<AuditLog> auditLogs) throws Throwable {
@After(value = "(execution(* org.genesys.blocks.auditlog.persistence.AuditLogRepository.save(..)) || execution(* org.genesys.blocks.auditlog.persistence.AuditLogRepository.saveAndFlush(..))) && args(auditLog)")
public void afterSaveAuditLogs(final JoinPoint joinPoint, final AuditLog auditLog) throws Throwable {
afterSaveAuditLogs(null, List.of(auditLog));
}
@After(value = "execution(* org.genesys.blocks.auditlog.persistence.AuditLogRepository.saveAll(Iterable)) && args(auditLogs)")
public void afterSaveAuditLogs(final JoinPoint joinPoint, final Collection<AuditLog> auditLogs) throws Throwable {
LOG.trace("Checking {} saved auditLogs, cpk={}", auditLogs.size(), this.accessionClassPk);
var changedAccessions = new HashMap<Long, HashMap<String, Pair<Object, Object>>>();
auditLogs.stream().filter(this::isAccessionChangeLog).forEach(auditLog -> {
var changes = changedAccessions.get(auditLog.getEntityId());
if (changes == null) {
changedAccessions.put(auditLog.getEntityId(), changes = new HashMap<String, Pair<Object, Object>>());
}
LOG.trace("{}#{} {} -> {}", auditLog.getEntityId(), auditLog.getPropertyName(), auditLog.getPreviousState(), auditLog.getNewState());
LOG.trace("{}#{} {} -> {}", auditLog.getEntityId(), auditLog.getPropertyName(), auditLog.getPreviousEntity(), auditLog.getNewEntity());
changes.put(auditLog.getPropertyName(), Pair.of(auditLog.getPreviousEntity(), auditLog.getNewEntity()));
});
changedAccessions.forEach((accessionId, changes) -> {
......@@ -204,7 +214,7 @@ public class AccessionTriggers implements InitializingBean {
private void recordAccessionNumberIfNeeded(long accessionId, String oldNumber, String newNumber, String oldNumberPart1, String newNumberPart1) {
LOG.trace("Recording name change aid={} {}/{} -> {}/{}", accessionId, oldNumberPart1, oldNumber, newNumberPart1, newNumber);
if (oldNumber != null && !newNumber.equals(oldNumber)) {
if (newNumber != null && !newNumber.equals(oldNumber)) {
LOG.debug("Recording name change aid={} {}/{} -> {}/{}", accessionId, oldNumberPart1, oldNumber, newNumberPart1, newNumber);
var accession = new Accession(accessionId);
......@@ -231,6 +241,7 @@ public class AccessionTriggers implements InitializingBean {
action.setStartedDateCode(CommunityCodeValues.DATE_FORMAT_DATETIME.value);
action.setCompletedDateCode(CommunityCodeValues.DATE_FORMAT_DATETIME.value);
action = actionService.create(action);
LOG.debug("Added action {}: {}", action.getActionNameCode(), action.getNote());
assert (action != null);
} else {
LOG.trace("Not recording name change {} {}", oldNumber, newNumber);
......@@ -256,7 +267,7 @@ public class AccessionTriggers implements InitializingBean {
}
private void recordAccessionSpeciesChangesIfNeeded(long accessionId, TaxonomySpecies oldTs, TaxonomySpecies newTs) {
LOG.debug("recordAccessionSpeciesChangesIfNeeded: orig.id={} curr=", oldTs, newTs);
LOG.debug("recordAccessionSpeciesChangesIfNeeded: orig.id={} curr=", oldTs.getId(), newTs.getId());
if (oldTs != null && !Objects.equals(oldTs.getId(), newTs.getId())) {
AccessionInvAnnotation annotation = new AccessionInvAnnotation();
annotation.setAnnotationTypeCode(CommunityCodeValues.ANNOTATION_TYPE_RE_IDENT.value);
......
......@@ -21,12 +21,14 @@ import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.gringlobal.api.v1.impl.InventoryController;
import org.gringlobal.api.v1.impl.InventoryViabilityController;
import org.gringlobal.api.v1.impl.InventoryViabilityController.InventoryViabilityDataController;
import org.gringlobal.model.Cooperator;
import org.gringlobal.model.Inventory;
import org.gringlobal.model.InventoryViability;
......@@ -48,6 +50,8 @@ import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.databind.node.ObjectNode;
/**
* @author Maxym Borodenko
......@@ -502,6 +506,85 @@ public class InventoryViabilityControllerTest extends AbstractApiV1Test {
/*@formatter:on*/
}
@Test
public void testCreateViabilityData() throws Exception {
var inventory = addInventoryToDB(addAccessionToDB());
var viability = new InventoryViability();
viability.setInventory(new Inventory(inventory.getId()));
viability.setTestedDate(new Date());
viability.setNote("Test");
viability = viabilityRepository.save(viability);
assertThat(viability.getId(), not(nullValue()));
var viabilityData = new InventoryViabilityData();
viabilityData.setInventoryViability(new InventoryViability(viability.getId()));
viabilityData.setReplicationNumber(1);
viabilityData.setCountNumber(1);
viabilityData.setCountDate(new Date());
viabilityData.setCounterCooperator(new Cooperator(cooperator.getId()));
viabilityData.setReplicationCount(20);
viabilityData.setNormalCount(10);
viabilityData.setAbnormalCount(1);
/*@formatter:off*/
var responseJson = mockMvc
.perform(post(InventoryViabilityDataController.API_URL)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.characterEncoding("UTF8")
.content(clientMapper.writeValueAsString(viabilityData).replaceFirst("\\\"inventoryViability\\\":(\\d+),", "\"inventoryViability\":{\"id\":$1},"))
)
.andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$", notNullValue()))
.andExpect(jsonPath("$.id", is(greaterThan(0))))
.andExpect(jsonPath("$.inventoryViability", is(viability.getId().intValue())))
.andExpect(jsonPath("$.countDate").isString())
.andExpect(jsonPath("$.countNumber", is(1)))
.andExpect(jsonPath("$.replicationNumber", is(1)))
.andExpect(jsonPath("$.counterCooperator").isMap())
.andExpect(jsonPath("$.counterCooperator.id", is(cooperator.getId().intValue())))
// .andExpect(jsonPath("$.counterCooperator.firstName").isString())
.andExpect(jsonPath("$.replicationCount", is(20)))
.andExpect(jsonPath("$.normalCount", is(10)))
.andExpect(jsonPath("$.abnormalCount", is(1)))
.andReturn().getResponse().getContentAsString(Charset.forName("UTF8"))
;
/*@formatter:on*/
var response = (ObjectNode) clientMapper.readTree(responseJson);
assertThat(response.get("id"), notNullValue());
viabilityData.setId(response.get("id").asLong());
viabilityData.setNormalCount(9);
/*@formatter:off*/
mockMvc
.perform(put(InventoryViabilityDataController.API_URL)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.characterEncoding("UTF8")
.content(clientMapper.writeValueAsString(viabilityData).replaceFirst("\\\"inventoryViability\\\":(\\d+),", "\"inventoryViability\":{\"id\":$1},"))
)
// .andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$", notNullValue()))
.andExpect(jsonPath("$.id", is(greaterThan(0))))
.andExpect(jsonPath("$.inventoryViability", is(viability.getId().intValue())))
.andExpect(jsonPath("$.countDate").isString())
.andExpect(jsonPath("$.countNumber", is(1)))
.andExpect(jsonPath("$.replicationNumber", is(1)))
.andExpect(jsonPath("$.counterCooperator").isMap())
.andExpect(jsonPath("$.counterCooperator.id", is(cooperator.getId().intValue())))
// .andExpect(jsonPath("$.counterCooperator.firstName").isString())
.andExpect(jsonPath("$.replicationCount", is(20)))
.andExpect(jsonPath("$.normalCount", is(9)))
.andExpect(jsonPath("$.abnormalCount", is(1)))
;
/*@formatter:on*/
}
private InventoryViability buildViability() {
return buildViability(addInventoryToDB(addAccessionToDB()));
}
......
......@@ -98,7 +98,8 @@ public class MethodControllerTest extends AbstractApiV1Test {
.andExpect(jsonPath("$.ownedBy", is(AbstractServicesTest.USER_CURATOR1)))
.andExpect(jsonPath("$.studyReasonCode", is(STUDY_REASON_CODE_1)))
.andExpect(jsonPath("$.name", is(METHOD_NAME_1)))
.andExpect(jsonPath("$.geography", is(nullValue())))
.andExpect(jsonPath("$.geography", is(notNullValue())))
.andExpect(jsonPath("$.geography.id", is(geography.getId().intValue())))
;
}
......@@ -156,8 +157,8 @@ public class MethodControllerTest extends AbstractApiV1Test {
.andExpect(jsonPath("$.ownedBy", is(AbstractServicesTest.USER_CURATOR1)))
.andExpect(jsonPath("$.studyReasonCode", is(STUDY_REASON_CODE_2)))
.andExpect(jsonPath("$.name", is(METHOD_NAME_2)))
// .andExpect(jsonPath("$.geography", is(notNullValue())))
// .andExpect(jsonPath("$.geography.id", is(geography.getId().intValue())))
.andExpect(jsonPath("$.geography", is(notNullValue())))
.andExpect(jsonPath("$.geography.id", is(geography.getId().intValue())))
;
assertThat(methodRepository.count(), is(1L));
......
......@@ -189,6 +189,7 @@ public class InventoryViabilitySecurityTest extends AbstractSecurityTest {
replicate1.setNormalCount(20);
inventoryViabilityDataService.create(replicate1);
replicate1.setId(null);
replicate1.setCountNumber(2);
replicate1.setCountDate(new Date());
replicate1.setAbnormalCount(10);
......
......@@ -205,8 +205,8 @@ public class AccessionServiceTest extends AbstractServicesTest {
assertThat(accessionInvNameRepository.count(), is(2L));
List<AccessionInvName> allNames = accessionInvNameRepository.findAll();
assertThat(allNames.stream().anyMatch(a -> a.getPlantName().equals(accession.getAccessionNumber())), is(true));
assertThat(allNames.stream().anyMatch(a -> a.getPlantName().equals(updated.getAccessionNumber())), is(true));
assertThat(allNames.stream().anyMatch(a -> a.getPlantName().equals("AccessionNumberPart1")), is(true));
assertThat(allNames.stream().anyMatch(a -> a.getPlantName().equals("AccessionNumberPart1 part3")), is(true));
// assert that name is registered with name group
var nameGroup = new NameGroup();
......@@ -215,12 +215,15 @@ public class AccessionServiceTest extends AbstractServicesTest {
updated.setAccessionNumberPart1("TMe");
updated.setAccessionNumberPart2(-1l);
updated.setAccessionNumberPart3("A");
var newUpdated = accessionService.update(updated);
assertThat(accessionInvNameRepository.count(), is(3L));
allNames = accessionInvNameRepository.findAll();
// A name with NameGroup exists!
assertThat(allNames.stream().anyMatch(a -> a.getPlantName().equals(newUpdated.getAccessionNumber()) && a.getNameGroup() != null && savedNameGroup.getId().equals(a.getNameGroup().getId())), is(true));
assertThat(allNames.stream().anyMatch(a -> a.getPlantName().equals("AccessionNumberPart1")), is(true));
assertThat(allNames.stream().anyMatch(a -> a.getPlantName().equals("AccessionNumberPart1 part3")), is(true));
assertThat(allNames.stream().anyMatch(a -> a.getPlantName().equals("TMe 1 A") && a.getNameGroup() != null && savedNameGroup.getGroupName().equals("TMe")), is(true));
}
......
......@@ -223,6 +223,7 @@ public class InventoryViabilityServiceTest extends AbstractServicesTest {
assertThat(inventoryViabilityData1.getCountNumber(), is(1));
assertThat(inventoryViabilityData1.getCounterCooperator(), not(nullValue()));
inventoryViabilityData1.setId(null);
// Test database constraint violation
assertThrows(DataIntegrityViolationException.class, () -> inventoryViabilityDataService.create(data1));
......@@ -272,10 +273,13 @@ public class InventoryViabilityServiceTest extends AbstractServicesTest {
viabilityData.setReplicationCount(6); // count is 6, sum must be less than 6
assertThrows(InvalidApiUsageException.class, () -> inventoryViabilityDataService.create(viabilityData));
assertThat(inventoryViabilityDataRepository.count(), is(0l));
// set valid
viabilityData.setId(null);
viabilityData.setReplicationCount(10); // 1+2+3+4=10
var inventoryViabilityData1 = inventoryViabilityDataService.create(viabilityData);
assertThat(inventoryViabilityDataRepository.count(), is(1l));
assertThat(inventoryViabilityData1.getInventoryViability().getId(), is(inventoryViability.getId()));
assertThat(inventoryViabilityData1.getReplicationCount(), is(10));
assertThat(inventoryViabilityData1.getCountNumber(), is(1));
......@@ -320,6 +324,7 @@ public class InventoryViabilityServiceTest extends AbstractServicesTest {
assertThat(viabilityDataRep1.sumOfCounts(), is(55));
inventoryViabilityDataService.create(viabilityDataRep1);
// Replication 1, count 2
viabilityDataRep1.setId(null);
viabilityDataRep1.setCountNumber(2);
viabilityDataRep1.setCountDate(new Date());
viabilityDataRep1.setUnknownCount(5);
......@@ -342,6 +347,7 @@ public class InventoryViabilityServiceTest extends AbstractServicesTest {
assertThat(viabilityDataRep2.sumOfCounts(), is(57));
inventoryViabilityDataService.create(viabilityDataRep2);
// Replication 2, count 2
viabilityDataRep2.setId(null);
viabilityDataRep2.setCountNumber(2);
viabilityDataRep2.setCountDate(new Date());
viabilityDataRep2.setUnknownCount(3);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment