fix:开发完毕

This commit is contained in:
彭帅
2026-05-28 17:25:32 +08:00
parent 50879a71da
commit c5d4d7a7e1
63 changed files with 4960 additions and 851 deletions

View File

@@ -0,0 +1,115 @@
package org.brapi.test.BrAPITestServer.controller.germ;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.brapi.test.BrAPITestServer.controller.core.BrAPIController;
import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerException;
import org.brapi.test.BrAPITestServer.model.dto.germ.GermplasmInstituteRecord;
import org.brapi.test.BrAPITestServer.model.dto.germ.GermplasmInstituteWriteRequest;
import org.brapi.test.BrAPITestServer.service.germ.GermplasmService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletRequest;
@RestController
public class GermplasmProfileWriteController extends BrAPIController {
private static final Logger log = LoggerFactory.getLogger(GermplasmProfileWriteController.class);
private final GermplasmService germplasmService;
private final HttpServletRequest request;
@Autowired
public GermplasmProfileWriteController(GermplasmService germplasmService, HttpServletRequest request) {
this.germplasmService = germplasmService;
this.request = request;
}
@CrossOrigin
@RequestMapping(value = "/germplasm/{germplasmDbId}/institutes", produces = {
"application/json" }, method = RequestMethod.GET)
public ResponseEntity<Map<String, Object>> germplasmGermplasmDbIdInstitutesGet(
@PathVariable("germplasmDbId") String germplasmDbId,
@RequestHeader(value = "Authorization", required = false) String authorization)
throws BrAPIServerException {
log.debug("Request: " + request.getRequestURI());
validateSecurityContext(request, "ROLE_ANONYMOUS", "ROLE_USER");
validateAcceptHeader(request);
List<GermplasmInstituteRecord> data = germplasmService.findInstitutes(germplasmDbId);
Map<String, Object> result = new HashMap<>();
result.put("data", data);
return ResponseEntity.ok(wrapOk(result));
}
@CrossOrigin
@RequestMapping(value = "/germplasm/{germplasmDbId}/institutes", produces = {
"application/json" }, consumes = { "application/json" }, method = RequestMethod.POST)
public ResponseEntity<Map<String, Object>> germplasmGermplasmDbIdInstitutesPost(
@PathVariable("germplasmDbId") String germplasmDbId,
@RequestBody GermplasmInstituteWriteRequest body,
@RequestHeader(value = "Authorization", required = false) String authorization)
throws BrAPIServerException {
log.debug("Request: " + request.getRequestURI());
validateSecurityContext(request, "ROLE_USER");
validateAcceptHeader(request);
GermplasmInstituteRecord data = germplasmService.saveInstitute(germplasmDbId, body);
Map<String, Object> result = new HashMap<>();
result.put("data", List.of(data));
return ResponseEntity.ok(wrapOk(result));
}
@CrossOrigin
@RequestMapping(value = "/germplasm/{germplasmDbId}/institutes/{instituteDbId}", produces = {
"application/json" }, consumes = { "application/json" }, method = RequestMethod.PUT)
public ResponseEntity<Map<String, Object>> germplasmGermplasmDbIdInstitutesInstituteDbIdPut(
@PathVariable("germplasmDbId") String germplasmDbId,
@PathVariable("instituteDbId") String instituteDbId,
@RequestBody GermplasmInstituteWriteRequest body,
@RequestHeader(value = "Authorization", required = false) String authorization)
throws BrAPIServerException {
log.debug("Request: " + request.getRequestURI());
validateSecurityContext(request, "ROLE_USER");
validateAcceptHeader(request);
GermplasmInstituteRecord data = germplasmService.updateInstitute(germplasmDbId, instituteDbId, body);
Map<String, Object> result = new HashMap<>();
result.put("data", List.of(data));
return ResponseEntity.ok(wrapOk(result));
}
@CrossOrigin
@RequestMapping(value = "/germplasm/{germplasmDbId}/institutes/{instituteDbId}", produces = {
"application/json" }, method = RequestMethod.DELETE)
public ResponseEntity<Map<String, Object>> germplasmGermplasmDbIdInstitutesInstituteDbIdDelete(
@PathVariable("germplasmDbId") String germplasmDbId,
@PathVariable("instituteDbId") String instituteDbId,
@RequestHeader(value = "Authorization", required = false) String authorization)
throws BrAPIServerException {
log.debug("Request: " + request.getRequestURI());
validateSecurityContext(request, "ROLE_USER");
validateAcceptHeader(request);
GermplasmInstituteRecord data = germplasmService.deleteInstitute(germplasmDbId, instituteDbId);
Map<String, Object> result = new HashMap<>();
result.put("data", List.of(data));
return ResponseEntity.ok(wrapOk(result));
}
private Map<String, Object> wrapOk(Map<String, Object> result) {
Map<String, Object> response = new HashMap<>();
response.put("metadata", generateEmptyMetadata());
response.put("result", result);
return response;
}
}

View File

@@ -0,0 +1,51 @@
package org.brapi.test.BrAPITestServer.model.dto.germ;
public class GermplasmInstituteRecord {
private String instituteDbId;
private String instituteType;
private String instituteCode;
private String instituteName;
private String instituteAddress;
public String getInstituteDbId() {
return instituteDbId;
}
public void setInstituteDbId(String instituteDbId) {
this.instituteDbId = instituteDbId;
}
public String getInstituteType() {
return instituteType;
}
public void setInstituteType(String instituteType) {
this.instituteType = instituteType;
}
public String getInstituteCode() {
return instituteCode;
}
public void setInstituteCode(String instituteCode) {
this.instituteCode = instituteCode;
}
public String getInstituteName() {
return instituteName;
}
public void setInstituteName(String instituteName) {
this.instituteName = instituteName;
}
public String getInstituteAddress() {
return instituteAddress;
}
public void setInstituteAddress(String instituteAddress) {
this.instituteAddress = instituteAddress;
}
}

View File

@@ -0,0 +1,51 @@
package org.brapi.test.BrAPITestServer.model.dto.germ;
public class GermplasmInstituteWriteRequest {
private String instituteDbId;
private String instituteType;
private String instituteCode;
private String instituteName;
private String instituteAddress;
public String getInstituteDbId() {
return instituteDbId;
}
public void setInstituteDbId(String instituteDbId) {
this.instituteDbId = instituteDbId;
}
public String getInstituteType() {
return instituteType;
}
public void setInstituteType(String instituteType) {
this.instituteType = instituteType;
}
public String getInstituteCode() {
return instituteCode;
}
public void setInstituteCode(String instituteCode) {
this.instituteCode = instituteCode;
}
public String getInstituteName() {
return instituteName;
}
public void setInstituteName(String instituteName) {
this.instituteName = instituteName;
}
public String getInstituteAddress() {
return instituteAddress;
}
public void setInstituteAddress(String instituteAddress) {
this.instituteAddress = instituteAddress;
}
}

View File

@@ -0,0 +1,8 @@
package org.brapi.test.BrAPITestServer.repository.germ;
import org.brapi.test.BrAPITestServer.model.entity.germ.GermplasmInstituteEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface GermplasmInstituteRepository extends JpaRepository<GermplasmInstituteEntity, String> {
}

View File

@@ -11,6 +11,8 @@ import jakarta.validation.Valid;
import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerDbIdNotFoundException;
import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerException;
import org.brapi.test.BrAPITestServer.model.dto.germ.GermplasmInstituteRecord;
import org.brapi.test.BrAPITestServer.model.dto.germ.GermplasmInstituteWriteRequest;
import org.brapi.test.BrAPITestServer.model.entity.core.CropEntity;
import org.brapi.test.BrAPITestServer.model.entity.germ.BreedingMethodEntity;
import org.brapi.test.BrAPITestServer.model.entity.germ.DonorEntity;
@@ -22,6 +24,7 @@ import org.brapi.test.BrAPITestServer.model.entity.germ.GermplasmSynonymEntity;
import org.brapi.test.BrAPITestServer.model.entity.germ.PedigreeNodeEntity;
import org.brapi.test.BrAPITestServer.model.entity.pheno.TaxonEntity;
import org.brapi.test.BrAPITestServer.repository.germ.GermplasmDonorRepository;
import org.brapi.test.BrAPITestServer.repository.germ.GermplasmInstituteRepository;
import org.brapi.test.BrAPITestServer.repository.germ.GermplasmRepository;
import org.brapi.test.BrAPITestServer.service.DateUtility;
import org.brapi.test.BrAPITestServer.service.GeoJSONUtility;
@@ -61,14 +64,17 @@ public class GermplasmService {
private final GermplasmRepository germplasmRepository;
private final GermplasmDonorRepository donorRepository;
private final GermplasmInstituteRepository instituteRepository;
private final BreedingMethodService breedingMethodService;
private final CropService cropService;
@Autowired
public GermplasmService(GermplasmRepository germplasmRepository, GermplasmDonorRepository donorRepository,
BreedingMethodService breedingMethodService, CropService cropService) {
GermplasmInstituteRepository instituteRepository, BreedingMethodService breedingMethodService,
CropService cropService) {
this.germplasmRepository = germplasmRepository;
this.donorRepository = donorRepository;
this.instituteRepository = instituteRepository;
this.breedingMethodService = breedingMethodService;
this.cropService = cropService;
@@ -630,4 +636,119 @@ public class GermplasmService {
return dupInstitutes;
}
public List<GermplasmInstituteRecord> findInstitutes(String germplasmDbId) throws BrAPIServerException {
GermplasmEntity entity = getGermplasmEntity(germplasmDbId, HttpStatus.NOT_FOUND);
if (entity.getInstitutes() == null) {
return new ArrayList<>();
}
return entity.getInstitutes().stream().map(this::convertInstituteRecord).collect(Collectors.toList());
}
public GermplasmInstituteRecord saveInstitute(String germplasmDbId, GermplasmInstituteWriteRequest request)
throws BrAPIServerException {
GermplasmEntity germplasm = getGermplasmEntity(germplasmDbId, HttpStatus.NOT_FOUND);
if (request.getInstituteType() == null || request.getInstituteType().isBlank()) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, "instituteType is required");
}
if (request.getInstituteDbId() != null
&& instituteRepository.findById(request.getInstituteDbId()).isPresent()) {
throw new BrAPIServerException(HttpStatus.CONFLICT,
"Institute already exists: " + request.getInstituteDbId());
}
GermplasmInstituteEntity entity = new GermplasmInstituteEntity();
if (request.getInstituteDbId() != null && !request.getInstituteDbId().isBlank()) {
entity.setId(request.getInstituteDbId().trim());
}
applyInstituteRequest(entity, germplasm, request);
assertInstituteUnique(germplasm, entity.getInstituteType(), entity.getInstituteCode(), null);
return convertInstituteRecord(instituteRepository.save(entity));
}
public GermplasmInstituteRecord updateInstitute(String germplasmDbId, String instituteDbId,
GermplasmInstituteWriteRequest request) throws BrAPIServerException {
GermplasmEntity germplasm = getGermplasmEntity(germplasmDbId, HttpStatus.NOT_FOUND);
GermplasmInstituteEntity entity = getInstituteEntity(instituteDbId);
if (entity.getGermplasm() == null || !germplasmDbId.equals(entity.getGermplasm().getId())) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, "Institute does not belong to this germplasm");
}
applyInstituteRequest(entity, germplasm, request);
assertInstituteUnique(germplasm, entity.getInstituteType(), entity.getInstituteCode(), entity.getId());
return convertInstituteRecord(instituteRepository.save(entity));
}
public GermplasmInstituteRecord deleteInstitute(String germplasmDbId, String instituteDbId)
throws BrAPIServerException {
GermplasmEntity germplasm = getGermplasmEntity(germplasmDbId, HttpStatus.NOT_FOUND);
GermplasmInstituteEntity entity = getInstituteEntity(instituteDbId);
if (entity.getGermplasm() == null || !germplasmDbId.equals(entity.getGermplasm().getId())) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, "Institute does not belong to this germplasm");
}
GermplasmInstituteRecord deleted = convertInstituteRecord(entity);
instituteRepository.delete(entity);
instituteRepository.flush();
if (germplasm.getInstitutes() != null) {
germplasm.getInstitutes().removeIf(item -> instituteDbId.equals(item.getId()));
}
return deleted;
}
private GermplasmInstituteEntity getInstituteEntity(String instituteDbId) throws BrAPIServerException {
return instituteRepository.findById(instituteDbId).orElseThrow(
() -> new BrAPIServerDbIdNotFoundException("institute", instituteDbId, HttpStatus.NOT_FOUND));
}
private void applyInstituteRequest(GermplasmInstituteEntity entity, GermplasmEntity germplasm,
GermplasmInstituteWriteRequest request) throws BrAPIServerException {
entity.setGermplasm(germplasm);
entity.setInstituteType(parseInstituteType(request.getInstituteType()));
entity.setInstituteCode(trimToNull(request.getInstituteCode()));
entity.setInstituteName(trimToNull(request.getInstituteName()));
entity.setInstituteAddress(trimToNull(request.getInstituteAddress()));
}
private InstituteTypeEnum parseInstituteType(String value) throws BrAPIServerException {
try {
return InstituteTypeEnum.valueOf(value.trim().toUpperCase());
} catch (Exception e) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST,
"instituteType must be one of HOST, DONOR, BREEDING, COLLECTING, REDUNDANT");
}
}
private String trimToNull(String value) {
if (value == null) {
return null;
}
String trimmed = value.trim();
return trimmed.isEmpty() ? null : trimmed;
}
private void assertInstituteUnique(GermplasmEntity germplasm, InstituteTypeEnum type, String code, String excludeId)
throws BrAPIServerException {
if (germplasm.getInstitutes() == null || code == null) {
return;
}
for (GermplasmInstituteEntity existing : germplasm.getInstitutes()) {
if (excludeId != null && excludeId.equals(existing.getId())) {
continue;
}
if (type.equals(existing.getInstituteType()) && code.equals(existing.getInstituteCode())) {
throw new BrAPIServerException(HttpStatus.CONFLICT,
"institute with same type and code already exists on this germplasm");
}
}
}
private GermplasmInstituteRecord convertInstituteRecord(GermplasmInstituteEntity entity) {
GermplasmInstituteRecord record = new GermplasmInstituteRecord();
record.setInstituteDbId(entity.getId());
if (entity.getInstituteType() != null) {
record.setInstituteType(entity.getInstituteType().name());
}
record.setInstituteCode(entity.getInstituteCode());
record.setInstituteName(entity.getInstituteName());
record.setInstituteAddress(entity.getInstituteAddress());
return record;
}
}

View File

@@ -1,7 +1,9 @@
package org.brapi.test.BrAPITestServer.service.germ;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -178,13 +180,56 @@ public class SeedLotService {
for (SeedLotNewTransactionRequest list : body) {
SeedLotTransactionEntity entity = new SeedLotTransactionEntity();
updateEntity(entity, list);
validateTransactionEntity(entity);
SeedLotTransactionEntity savedEntity = seedLotTransactionRepository.save(entity);
applyTransactionInventory(savedEntity);
savedValues.add(convertFromEntity(savedEntity));
}
return savedValues;
}
private void validateTransactionEntity(SeedLotTransactionEntity entity) throws BrAPIServerException {
SeedLotEntity fromSeedLot = entity.getFromSeedLot();
SeedLotEntity toSeedLot = entity.getToSeedLot();
if (fromSeedLot == null && toSeedLot == null) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST,
"from_seed_lot_id and to_seed_lot_id cannot both be empty");
}
if (fromSeedLot != null && toSeedLot != null && fromSeedLot.getId().equals(toSeedLot.getId())) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, "from_seed_lot_id cannot equal to_seed_lot_id");
}
if (entity.getAmount() == null || entity.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, "amount must be greater than 0");
}
if (fromSeedLot != null) {
BigDecimal currentAmount = fromSeedLot.getAmount() != null ? fromSeedLot.getAmount() : BigDecimal.ZERO;
if (entity.getAmount().compareTo(currentAmount) > 0) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST,
"Insufficient stock in source seed lot: " + fromSeedLot.getId());
}
}
}
private void applyTransactionInventory(SeedLotTransactionEntity entity) {
Date updatedAt = entity.getTimestamp() != null ? entity.getTimestamp() : new Date();
BigDecimal delta = entity.getAmount();
if (entity.getFromSeedLot() != null) {
SeedLotEntity fromSeedLot = entity.getFromSeedLot();
BigDecimal currentAmount = fromSeedLot.getAmount() != null ? fromSeedLot.getAmount() : BigDecimal.ZERO;
fromSeedLot.setAmount(currentAmount.subtract(delta));
fromSeedLot.setLastUpdated(updatedAt);
seedLotRepository.save(fromSeedLot);
}
if (entity.getToSeedLot() != null) {
SeedLotEntity toSeedLot = entity.getToSeedLot();
BigDecimal currentAmount = toSeedLot.getAmount() != null ? toSeedLot.getAmount() : BigDecimal.ZERO;
toSeedLot.setAmount(currentAmount.add(delta));
toSeedLot.setLastUpdated(updatedAt);
seedLotRepository.save(toSeedLot);
}
}
private SeedLot convertFromEntity(SeedLotEntity entity) {
SeedLot seedLot = new SeedLot();
UpdateUtility.convertFromEntity(entity, seedLot);