From 9a2a9433e57e1a91609b62e8c4fe330bd237dbff Mon Sep 17 00:00:00 2001 From: siarhei-charniak Date: Mon, 13 Jan 2025 17:46:15 +0300 Subject: [PATCH] MODBULKOPS-428 - Apply changes - MARC Bib records with administrative data (#343) --- .../controller/BulkOperationController.java | 12 +- .../entity/BulkOperationDataProcessing.java | 5 + .../processor/marc/MarcRulesValidator.java | 8 +- ...BulkOperationDataProcessingRepository.java | 4 +- .../BulkOperationRuleDetailsRepository.java | 1 + .../bulkops/service/BulkOperationService.java | 170 +++++++++++------- .../bulkops/service/LogFilesService.java | 1 + .../folio/bulkops/service/PreviewService.java | 25 ++- .../folio/bulkops/service/RuleService.java | 26 +-- .../util/UpdateOptionTypeToFieldResolver.java | 3 +- .../db/changelog/changelog-master.xml | 1 + ..._column_bulk_operation_data_processing.sql | 10 ++ ..._column_bulk_operation_data_processing.xml | 13 ++ .../bulk_operation_marc_rule_collection.json | 3 +- .../bulk_operation_rule_collection.json | 3 +- .../schemas/file_content_type.json | 1 + .../BulkOperationControllerTest.java | 12 +- .../marc/MarcInstanceDataProcessorTest.java | 4 +- ...OperationDataProcessingRepositoryTest.java | 2 +- .../service/BulkOperationServiceTest.java | 141 +++++++++++---- .../bulkops/service/PreviewServiceTest.java | 12 ++ .../bulkops/service/RuleServiceTest.java | 7 +- src/test/resources/files/instance_marc.json | 101 +++++++++++ 23 files changed, 414 insertions(+), 151 deletions(-) create mode 100644 src/main/resources/db/changelog/changes/11-01-2025_restore_id_column_bulk_operation_data_processing.sql create mode 100644 src/main/resources/db/changelog/changes/11-01-2025_restore_id_column_bulk_operation_data_processing.xml create mode 100644 src/test/resources/files/instance_marc.json diff --git a/src/main/java/org/folio/bulkops/controller/BulkOperationController.java b/src/main/java/org/folio/bulkops/controller/BulkOperationController.java index a3e83bdaa..567f48411 100644 --- a/src/main/java/org/folio/bulkops/controller/BulkOperationController.java +++ b/src/main/java/org/folio/bulkops/controller/BulkOperationController.java @@ -6,6 +6,7 @@ import static org.folio.bulkops.domain.dto.FileContentType.COMMITTING_CHANGES_ERROR_FILE; import static org.folio.bulkops.domain.dto.FileContentType.MATCHED_RECORDS_FILE; import static org.folio.bulkops.domain.dto.FileContentType.PROPOSED_CHANGES_FILE; +import static org.folio.bulkops.domain.dto.FileContentType.PROPOSED_CHANGES_MARC_FILE; import static org.folio.bulkops.domain.dto.FileContentType.RECORD_MATCHING_ERROR_FILE; import static org.folio.bulkops.domain.dto.FileContentType.TRIGGERING_FILE; import static org.folio.bulkops.util.Constants.CSV_EXTENSION; @@ -104,7 +105,7 @@ public ResponseEntity getPreviewByOperationId(UUID operationId, Bu @Override public ResponseEntity postContentUpdates(UUID operationId, BulkOperationRuleCollection bulkOperationRuleCollection) { var operation = bulkOperationService.getBulkOperationOrThrow(operationId); - var rules = ruleService.saveRules(bulkOperationRuleCollection); + var rules = ruleService.saveRules(operation, bulkOperationRuleCollection); if (INSTANCE_MARC.equals(operation.getEntityType())) { operation.setEntityType(INSTANCE); @@ -119,9 +120,10 @@ public ResponseEntity postContentUpdates(UUID opera @Override public ResponseEntity postMarcContentUpdates(UUID operationId, BulkOperationMarcRuleCollection bulkOperationMarcRuleCollection) { var operation = bulkOperationService.getBulkOperationOrThrow(operationId); + var rules = ruleService.saveMarcRules(operation, bulkOperationMarcRuleCollection); + operation.setEntityType(INSTANCE_MARC); bulkOperationRepository.save(operation); - var rules = ruleService.saveMarcRules(bulkOperationMarcRuleCollection); bulkOperationService.clearOperationProcessing(operation); @@ -157,9 +159,9 @@ public ResponseEntity downloadFileByOperationId( } else if (fileContentType == RECORD_MATCHING_ERROR_FILE) { path = bulkOperation.getLinkToMatchedRecordsErrorsCsvFile(); } else if (fileContentType == PROPOSED_CHANGES_FILE) { - path = INSTANCE_MARC.equals(bulkOperation.getEntityType()) ? - bulkOperation.getLinkToModifiedRecordsMarcFile() : - bulkOperation.getLinkToModifiedRecordsCsvFile(); + path = bulkOperation.getLinkToModifiedRecordsCsvFile(); + } else if (fileContentType == PROPOSED_CHANGES_MARC_FILE) { + path = bulkOperation.getLinkToModifiedRecordsMarcFile(); } else if (fileContentType == COMMITTED_RECORDS_FILE) { path = INSTANCE_MARC.equals(bulkOperation.getEntityType()) ? bulkOperation.getLinkToCommittedRecordsMarcFile() : diff --git a/src/main/java/org/folio/bulkops/domain/entity/BulkOperationDataProcessing.java b/src/main/java/org/folio/bulkops/domain/entity/BulkOperationDataProcessing.java index 2e0596f88..55d75f874 100644 --- a/src/main/java/org/folio/bulkops/domain/entity/BulkOperationDataProcessing.java +++ b/src/main/java/org/folio/bulkops/domain/entity/BulkOperationDataProcessing.java @@ -3,6 +3,8 @@ import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import java.time.LocalDateTime; @@ -23,6 +25,9 @@ @Table(name = "bulk_operation_data_processing") public class BulkOperationDataProcessing { @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private UUID id; + private UUID bulkOperationId; @Enumerated(EnumType.STRING) diff --git a/src/main/java/org/folio/bulkops/processor/marc/MarcRulesValidator.java b/src/main/java/org/folio/bulkops/processor/marc/MarcRulesValidator.java index bd1356e1e..56440f739 100644 --- a/src/main/java/org/folio/bulkops/processor/marc/MarcRulesValidator.java +++ b/src/main/java/org/folio/bulkops/processor/marc/MarcRulesValidator.java @@ -5,15 +5,19 @@ import org.folio.bulkops.exception.RuleValidationException; import org.springframework.stereotype.Component; +import java.util.regex.Pattern; + @Component public class MarcRulesValidator { - private static final String VALID_TAG_REGEXP = "5\\d{2}|9\\d{2}"; + private static final Pattern TAG_PATTERN = Pattern.compile("\\d{3}"); + private static final Pattern UNSUPPORTED_TAG_PATTERN = Pattern.compile("00\\d"); private static final String NOT_SUPPORTED_BULK_EDIT_FIELD_MESSAGE = "Bulk edit of %s field is not supported"; public void validate(BulkOperationMarcRule bulkOperationMarcRule) throws RuleValidationException { var tag = bulkOperationMarcRule.getTag(); - if (StringUtils.isEmpty(tag) || StringUtils.isNotEmpty(tag) && !tag.matches(VALID_TAG_REGEXP)) { + if (StringUtils.isEmpty(tag) || !TAG_PATTERN.matcher(tag).matches() + || UNSUPPORTED_TAG_PATTERN.matcher(tag).matches()) { throw new RuleValidationException(String.format(NOT_SUPPORTED_BULK_EDIT_FIELD_MESSAGE, tag)); } } diff --git a/src/main/java/org/folio/bulkops/repository/BulkOperationDataProcessingRepository.java b/src/main/java/org/folio/bulkops/repository/BulkOperationDataProcessingRepository.java index 7b6fac540..5a5103089 100644 --- a/src/main/java/org/folio/bulkops/repository/BulkOperationDataProcessingRepository.java +++ b/src/main/java/org/folio/bulkops/repository/BulkOperationDataProcessingRepository.java @@ -1,5 +1,6 @@ package org.folio.bulkops.repository; +import java.util.List; import java.util.UUID; import org.folio.bulkops.domain.entity.BulkOperationDataProcessing; import org.springframework.data.jpa.repository.JpaRepository; @@ -7,5 +8,6 @@ @Repository public interface BulkOperationDataProcessingRepository extends JpaRepository { - + List findAllByBulkOperationId(UUID bulkOperationId); + void deleteAllByBulkOperationId(UUID bulkOperationId); } diff --git a/src/main/java/org/folio/bulkops/repository/BulkOperationRuleDetailsRepository.java b/src/main/java/org/folio/bulkops/repository/BulkOperationRuleDetailsRepository.java index cdbd9f5bc..560fc3e79 100644 --- a/src/main/java/org/folio/bulkops/repository/BulkOperationRuleDetailsRepository.java +++ b/src/main/java/org/folio/bulkops/repository/BulkOperationRuleDetailsRepository.java @@ -8,4 +8,5 @@ @Repository public interface BulkOperationRuleDetailsRepository extends JpaRepository { + void deleteAllByRuleId(UUID ruleId); } diff --git a/src/main/java/org/folio/bulkops/service/BulkOperationService.java b/src/main/java/org/folio/bulkops/service/BulkOperationService.java index 4615694b4..cc627e5fe 100644 --- a/src/main/java/org/folio/bulkops/service/BulkOperationService.java +++ b/src/main/java/org/folio/bulkops/service/BulkOperationService.java @@ -23,6 +23,7 @@ import static org.folio.bulkops.domain.dto.OperationStatusType.SAVED_IDENTIFIERS; import static org.folio.bulkops.domain.dto.OperationStatusType.SAVING_RECORDS_LOCALLY; import static org.folio.bulkops.util.Constants.FIELD_ERROR_MESSAGE_PATTERN; +import static org.folio.bulkops.util.Constants.MARC; import static org.folio.bulkops.util.ErrorCode.ERROR_MESSAGE_PATTERN; import static org.folio.bulkops.util.ErrorCode.ERROR_NOT_CONFIRM_CHANGES_S3_ISSUE; import static org.folio.bulkops.util.ErrorCode.ERROR_UPLOAD_IDENTIFIERS_S3_ISSUE; @@ -38,6 +39,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Objects; @@ -55,6 +57,7 @@ import org.folio.bulkops.domain.bean.BulkOperationsEntity; import org.folio.bulkops.domain.bean.ExportType; import org.folio.bulkops.domain.bean.ExportTypeSpecificParameters; +import org.folio.bulkops.domain.bean.ExtendedInstance; import org.folio.bulkops.domain.bean.Job; import org.folio.bulkops.domain.bean.JobStatus; import org.folio.bulkops.domain.bean.StateType; @@ -63,6 +66,7 @@ import org.folio.bulkops.domain.converter.BulkOperationsEntityCsvWriter; import org.folio.bulkops.domain.dto.ApproachType; import org.folio.bulkops.domain.dto.BulkOperationRuleCollection; +import org.folio.bulkops.domain.dto.BulkOperationMarcRuleCollection; import org.folio.bulkops.domain.dto.BulkOperationStart; import org.folio.bulkops.domain.dto.BulkOperationStep; import org.folio.bulkops.domain.dto.DataImportJobExecution; @@ -97,6 +101,7 @@ import org.marc4j.MarcStreamReader; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import com.fasterxml.jackson.core.JsonFactory; @@ -145,8 +150,8 @@ public class BulkOperationService { private static final int OPERATION_UPDATING_STEP = 100; private static final String PREVIEW_JSON_PATH_TEMPLATE = "%s/json/%s-Updates-Preview-%s.json"; - private static final String PREVIEW_CSV_PATH_TEMPLATE = "%s/%s-Updates-Preview-%s.csv"; - private static final String PREVIEW_MARC_PATH_TEMPLATE = "%s/%s-Updates-Preview-%s.mrc"; + private static final String PREVIEW_CSV_PATH_TEMPLATE = "%s/%s-Updates-Preview-CSV-%s.csv"; + private static final String PREVIEW_MARC_PATH_TEMPLATE = "%s/%s-Updates-Preview-MARC-%s.mrc"; private static final String CHANGED_JSON_PATH_TEMPLATE = "%s/json/%s-Changed-Records-%s.json"; private static final String CHANGED_CSV_PATH_TEMPLATE = "%s/%s-Changed-Records-%s.csv"; @@ -211,31 +216,16 @@ public BulkOperation triggerByQuery(UUID userId, QueryRequest queryRequest) { .build()); } - public void confirm(BulkOperation operation) { - + public void confirm(BulkOperationDataProcessing dataProcessing) { + var operationId = dataProcessing.getBulkOperationId(); + var operation = getBulkOperationOrThrow(operationId); operation.setStatus(DATA_MODIFICATION_IN_PROGRESS); bulkOperationRepository.save(operation); - if (operation.getEntityType() == INSTANCE_MARC) { - confirmForInstanceMarc(operation); - return; - } - operation.setProcessedNumOfRecords(0); - var operationId = operation.getId(); - + var ruleCollection = ruleService.getRules(dataProcessing.getBulkOperationId()); var clazz = resolveEntityClass(operation.getEntityType()); var extendedClazz = resolveExtendedEntityClass(operation.getEntityType()); - var ruleCollection = ruleService.getRules(operationId); - - var dataProcessing = dataProcessingRepository.save(BulkOperationDataProcessing.builder() - .bulkOperationId(operation.getId()) - .status(StatusType.ACTIVE) - .startTime(LocalDateTime.now()) - .totalNumOfRecords(operation.getTotalNumOfRecords()) - .processedNumOfRecords(0) - .build()); - var triggeringFileName = FilenameUtils.getBaseName(operation.getLinkToTriggeringCsvFile()); var modifiedJsonFileName = String.format(PREVIEW_JSON_PATH_TEMPLATE, operationId, LocalDate.now(), triggeringFileName); var modifiedPreviewCsvFileName = String.format(PREVIEW_CSV_PATH_TEMPLATE, operationId, LocalDate.now(), triggeringFileName); @@ -250,12 +240,12 @@ public void confirm(BulkOperation operation) { var processedNumOfRecords = 0; - if (iterator.hasNext()) { - operation.setLinkToModifiedRecordsCsvFile(modifiedPreviewCsvFileName); - } - while (iterator.hasNext()) { var original = iterator.next(); + if (INSTANCE_MARC.equals(operation.getEntityType()) && original instanceof ExtendedInstance extendedInstance + && !MARC.equals(extendedInstance.getEntity().getSource())) { + continue; + } var modified = processUpdate(original, operation, ruleCollection, extendedClazz); List bulkOperationExecutionContents = new ArrayList<>(); if (Objects.nonNull(modified)) { @@ -286,37 +276,32 @@ public void confirm(BulkOperation operation) { } } - operation.setLinkToModifiedRecordsJsonFile(modifiedJsonFileName); + if (processedNumOfRecords > 0) { + operation = getBulkOperationOrThrow(operationId); + operation.setLinkToModifiedRecordsCsvFile(modifiedPreviewCsvFileName); + operation.setLinkToModifiedRecordsJsonFile(modifiedJsonFileName); + bulkOperationRepository.save(operation); + } dataProcessing.setProcessedNumOfRecords(processedNumOfRecords); dataProcessingRepository.save(dataProcessing); - operation.setApproach(IN_APP); - operation.setStatus(OperationStatusType.REVIEW_CHANGES); - operation.setProcessedNumOfRecords(processedNumOfRecords); - - bulkOperationRepository.findById(operation.getId()).ifPresent(op -> operation.setCommittedNumOfErrors(op.getCommittedNumOfErrors())); + handleProcessingCompletion(operationId); } catch (S3ClientException e) { - handleException(operation, dataProcessing, ERROR_NOT_CONFIRM_CHANGES_S3_ISSUE, e); + handleException(operation.getId(), dataProcessing, ERROR_NOT_CONFIRM_CHANGES_S3_ISSUE, e); } catch (Exception e) { - handleException(operation, dataProcessing, "Confirm failed", e); - } finally { - bulkOperationRepository.save(operation); + handleException(operation.getId(), dataProcessing, "Confirm failed", e); } } - private void confirmForInstanceMarc(BulkOperation operation) { - operation.setProcessedNumOfRecords(0); - var operationId = operation.getId(); - var ruleCollection = ruleService.getMarcRules(operationId); - - var dataProcessing = dataProcessingRepository.save(BulkOperationDataProcessing.builder() - .bulkOperationId(operation.getId()) - .status(StatusType.ACTIVE) - .startTime(LocalDateTime.now()) - .totalNumOfRecords(operation.getTotalNumOfRecords()) - .processedNumOfRecords(0) - .build()); + private void confirmForInstanceMarc(BulkOperationDataProcessing dataProcessing) { + var operationId = dataProcessing.getBulkOperationId(); + var operation = getBulkOperationOrThrow(operationId); + if (!DATA_MODIFICATION_IN_PROGRESS.equals(operation.getStatus())) { + operation.setStatus(DATA_MODIFICATION_IN_PROGRESS); + bulkOperationRepository.save(operation); + } + var ruleCollection = ruleService.getMarcRules(dataProcessing.getBulkOperationId()); var processedNumOfRecords = 0; if (nonNull(operation.getLinkToMatchedRecordsMarcFile())) { var triggeringFileName = FilenameUtils.getBaseName(operation.getLinkToTriggeringCsvFile()); @@ -327,7 +312,9 @@ private void confirmForInstanceMarc(BulkOperation operation) { var currentDate = new Date(); while (matchedRecordsReader.hasNext()) { var marcRecord = matchedRecordsReader.next(); - marcInstanceDataProcessor.update(operation, marcRecord, ruleCollection, currentDate); + if (!ruleCollection.getBulkOperationMarcRules().isEmpty()) { + marcInstanceDataProcessor.update(operation, marcRecord, ruleCollection, currentDate); + } writerForModifiedPreviewMarcFile.writeRecord(marcRecord); processedNumOfRecords++; @@ -340,29 +327,31 @@ private void confirmForInstanceMarc(BulkOperation operation) { dataProcessingRepository.save(dataProcessing); } } - operation.setLinkToModifiedRecordsMarcFile(modifiedMarcFileName); + + if (processedNumOfRecords > 0) { + operation = getBulkOperationOrThrow(operationId); + operation.setLinkToModifiedRecordsMarcFile(modifiedMarcFileName); + bulkOperationRepository.save(operation); + } dataProcessing.setProcessedNumOfRecords(processedNumOfRecords); dataProcessingRepository.save(dataProcessing); - operation.setApproach(IN_APP); - operation.setStatus(OperationStatusType.REVIEW_CHANGES); - operation.setProcessedNumOfRecords(processedNumOfRecords); - - bulkOperationRepository.findById(operation.getId()).ifPresent(op -> operation.setCommittedNumOfErrors(op.getCommittedNumOfErrors())); + handleProcessingCompletion(operationId); } catch (S3ClientException e) { - handleException(operation, dataProcessing, ERROR_NOT_CONFIRM_CHANGES_S3_ISSUE, e); + handleException(operation.getId(), dataProcessing, ERROR_NOT_CONFIRM_CHANGES_S3_ISSUE, e); } catch (Exception e) { - handleException(operation, dataProcessing, "Confirm failed", e); + handleException(operation.getId(), dataProcessing, "Confirm failed", e); } } else { log.error("No link to MARC file, failing operation"); dataProcessingRepository.save(dataProcessing .withStatus(StatusType.FAILED) .withEndTime(LocalDateTime.now())); + operation = getBulkOperationOrThrow(operationId); operation.setStatus(OperationStatusType.REVIEWED_NO_MARC_RECORDS); operation.setEndTime(LocalDateTime.now()); + bulkOperationRepository.save(operation); } - bulkOperationRepository.save(operation); } public void writeBeanToCsv(BulkOperation operation, BulkOperationsEntityCsvWriter csvWriter, BulkOperationsEntity bean, List bulkOperationExecutionContents) throws CsvRequiredFieldEmptyException, CsvDataTypeMismatchException { @@ -541,7 +530,7 @@ public BulkOperation startBulkOperation(UUID bulkOperationId, UUID xOkapiUserId, executor.execute(getRunnableWithCurrentFolioContext(() -> apply(operation))); } else { logFilesService.removeModifiedFiles(operation); - executor.execute(getRunnableWithCurrentFolioContext(() -> confirm(operation))); + launchProcessing(operation); } return operation; } else { @@ -653,15 +642,11 @@ private String uploadCsvFile(UUID dataExportJobId, MultipartFile file) throws Bu } } + @Transactional public void clearOperationProcessing(BulkOperation operation) { - var processing = dataProcessingRepository.findById(operation.getId()); - - if (processing.isPresent()) { - dataProcessingRepository.deleteById(processing.get().getBulkOperationId()); - - operation.setStatus(DATA_MODIFICATION); - bulkOperationRepository.save(operation); - } + dataProcessingRepository.deleteAllByBulkOperationId(operation.getId()); + operation.setStatus(DATA_MODIFICATION); + bulkOperationRepository.save(operation); } public BulkOperation getOperationById(UUID bulkOperationId) { @@ -740,7 +725,8 @@ private void handleException(BulkOperation operation, String message, Exception operation.setEndTime(LocalDateTime.now()); } - private void handleException(BulkOperation operation, BulkOperationDataProcessing dataProcessing, String message, Exception exception) { + private void handleException(UUID operationId, BulkOperationDataProcessing dataProcessing, String message, Exception exception) { + var operation = getBulkOperationOrThrow(operationId); dataProcessingRepository.save(dataProcessing .withStatus(StatusType.FAILED) .withEndTime(LocalDateTime.now())); @@ -748,5 +734,55 @@ private void handleException(BulkOperation operation, BulkOperationDataProcessin operation.setErrorMessage(format(ERROR_MESSAGE_PATTERN, message, exception.getMessage())); operation.setStatus(OperationStatusType.FAILED); operation.setEndTime(LocalDateTime.now()); + bulkOperationRepository.save(operation); + } + + private void launchProcessing(BulkOperation operation) { + var folioProcessing = dataProcessingRepository.save(BulkOperationDataProcessing.builder() + .bulkOperationId(operation.getId()) + .status(StatusType.ACTIVE) + .startTime(LocalDateTime.now()) + .totalNumOfRecords(operation.getTotalNumOfRecords()) + .processedNumOfRecords(0) + .build()); + + if (INSTANCE_MARC.equals(operation.getEntityType())) { + var marcProcessing = dataProcessingRepository.save(BulkOperationDataProcessing.builder() + .bulkOperationId(operation.getId()) + .status(StatusType.ACTIVE) + .startTime(LocalDateTime.now()) + .totalNumOfRecords(operation.getTotalNumOfRecords()) + .processedNumOfRecords(0) + .build()); + executor.execute(getRunnableWithCurrentFolioContext(() -> confirmForInstanceMarc(marcProcessing))); + } + executor.execute(getRunnableWithCurrentFolioContext(() -> confirm(folioProcessing))); + } + + private void handleProcessingCompletion(UUID operationId) { + bulkOperationRepository.findById(operationId).ifPresent(operation -> { + if (!FAILED.equals(operation.getStatus())) { + var processingList = dataProcessingRepository.findAllByBulkOperationId(operation.getId()); + if (isCompletedSuccessfully(processingList)) { + var processedNumOfRecords = processingList.stream() + .map(BulkOperationDataProcessing::getProcessedNumOfRecords) + .mapToInt(v -> v) + .max() + .orElseThrow(() -> new IllegalStateException("Failed to get processed num of records")); + operation.setApproach(IN_APP); + operation.setStatus(OperationStatusType.REVIEW_CHANGES); + operation.setProcessedNumOfRecords(processedNumOfRecords); + bulkOperationRepository.save(operation); + } + } else { + operation.setLinkToModifiedRecordsCsvFile(null); + operation.setLinkToModifiedRecordsMarcFile(null); + bulkOperationRepository.save(operation); + } + }); + } + + private boolean isCompletedSuccessfully(List list) { + return list.stream().allMatch(p -> StatusType.COMPLETED.equals(p.getStatus())); } } diff --git a/src/main/java/org/folio/bulkops/service/LogFilesService.java b/src/main/java/org/folio/bulkops/service/LogFilesService.java index 4e0d62275..f5402a4f2 100644 --- a/src/main/java/org/folio/bulkops/service/LogFilesService.java +++ b/src/main/java/org/folio/bulkops/service/LogFilesService.java @@ -111,5 +111,6 @@ public void removeModifiedFiles(BulkOperation bulkOperation) { remoteFileSystemClient.remove(bulkOperation.getLinkToModifiedRecordsMarcFile()); bulkOperation.setLinkToModifiedRecordsMarcFile(null); } + bulkOperationRepository.save(bulkOperation); } } diff --git a/src/main/java/org/folio/bulkops/service/PreviewService.java b/src/main/java/org/folio/bulkops/service/PreviewService.java index 24eb64237..8ef18cdb0 100644 --- a/src/main/java/org/folio/bulkops/service/PreviewService.java +++ b/src/main/java/org/folio/bulkops/service/PreviewService.java @@ -47,6 +47,7 @@ import java.util.Set; import java.util.UUID; import java.util.regex.Pattern; +import java.util.stream.Collectors; import com.opencsv.CSVReaderBuilder; import com.opencsv.bean.CsvCustomBindByName; @@ -65,7 +66,9 @@ import org.folio.bulkops.domain.bean.BulkOperationsEntity; import org.folio.bulkops.domain.bean.HoldingsRecord; import org.folio.bulkops.domain.bean.Item; +import org.folio.bulkops.domain.dto.BulkOperationRule; import org.folio.bulkops.domain.dto.BulkOperationRuleCollection; +import org.folio.bulkops.domain.dto.BulkOperationRuleRuleDetails; import org.folio.bulkops.domain.dto.BulkOperationMarcRuleCollection; import org.folio.bulkops.domain.dto.BulkOperationStep; import org.folio.bulkops.domain.dto.Cell; @@ -183,11 +186,11 @@ private boolean isMarcInstanceCommitPreview(BulkOperation operation) { } private UnifiedTable buildCompositePreview(BulkOperation bulkOperation, int offset, int limit, String linkToCsvFile, String linkToMarcFile) { - var csvTable = buildPreviewFromCsvFile(linkToCsvFile, Instance.class, offset, limit, bulkOperation); + var csvTable = buildPreviewFromCsvFile(linkToCsvFile, resolveEntityClass(bulkOperation.getEntityType()), offset, limit, bulkOperation); if (isNotEmpty(linkToMarcFile)) { referenceProvider.updateMappingRules(); - var rules = ruleService.getMarcRules(bulkOperation.getId()); - var changedOptionsSet = getChangedOptionsSet(rules); + var marcRules = ruleService.getMarcRules(bulkOperation.getId()); + var changedOptionsSet = getChangedOptionsSet(marcRules); var compositeTable = UnifiedTableHeaderBuilder.getEmptyTableWithHeaders(Instance.class); noteTableUpdater.extendTableWithInstanceNotesTypes(compositeTable, changedOptionsSet); var sourcePosition = getCellPositionByName(INSTANCE_SOURCE); @@ -211,11 +214,27 @@ private UnifiedTable buildCompositePreview(BulkOperation bulkOperation, int offs } } }); + forceVisibleAdministrativeDataHeaders(compositeTable, bulkOperation); return compositeTable; } + forceVisibleAdministrativeDataHeaders(csvTable, bulkOperation); return csvTable; } + private void forceVisibleAdministrativeDataHeaders(UnifiedTable unifiedTable, BulkOperation bulkOperation) { + var rules = ruleService.getRules(bulkOperation.getId()); + var forceVisibleFieldNames = rules.getBulkOperationRules().stream() + .map(BulkOperationRule::getRuleDetails) + .map(BulkOperationRuleRuleDetails::getOption) + .map(option -> UpdateOptionTypeToFieldResolver.getFieldByUpdateOptionType(option, INSTANCE)) + .collect(Collectors.toSet()); + unifiedTable.getHeader().forEach(header -> { + if (forceVisibleFieldNames.contains(header.getValue())) { + header.setForceVisible(true); + } + }); + } + private void enrichMarcWithAdministrativeData(UnifiedTable unifiedTable, BulkOperation bulkOperation) { var hridPosition = getCellPositionByName(INSTANCE_HRID); var hrids = unifiedTable.getRows().stream() diff --git a/src/main/java/org/folio/bulkops/service/RuleService.java b/src/main/java/org/folio/bulkops/service/RuleService.java index d46989475..b0ed3f3bf 100644 --- a/src/main/java/org/folio/bulkops/service/RuleService.java +++ b/src/main/java/org/folio/bulkops/service/RuleService.java @@ -4,14 +4,12 @@ import org.folio.bulkops.domain.dto.Action; import org.folio.bulkops.domain.dto.BulkOperationRule; -import org.folio.bulkops.domain.dto.BulkOperationMarcRule; import org.folio.bulkops.domain.dto.BulkOperationRuleCollection; import org.folio.bulkops.domain.dto.BulkOperationRuleRuleDetails; import org.folio.bulkops.domain.dto.BulkOperationMarcRuleCollection; -import org.folio.bulkops.exception.NotFoundException; +import org.folio.bulkops.domain.entity.BulkOperation; import org.folio.bulkops.mapper.MarcRulesMapper; import org.folio.bulkops.repository.BulkOperationMarcRuleRepository; -import org.folio.bulkops.repository.BulkOperationRepository; import org.folio.bulkops.repository.BulkOperationRuleDetailsRepository; import org.folio.bulkops.repository.BulkOperationRuleRepository; import org.springframework.stereotype.Service; @@ -24,16 +22,13 @@ public class RuleService { private final BulkOperationRuleRepository ruleRepository; private final BulkOperationRuleDetailsRepository ruleDetailsRepository; - private final BulkOperationRepository bulkOperationRepository; private final BulkOperationMarcRuleRepository marcRuleRepository; private final MarcRulesMapper marcRulesMapper; @Transactional - public BulkOperationRuleCollection saveRules(BulkOperationRuleCollection ruleCollection) { - ruleCollection.getBulkOperationRules().stream() - .map(BulkOperationRule::getBulkOperationId) - .distinct() - .forEach(ruleRepository::deleteAllByBulkOperationId); + public BulkOperationRuleCollection saveRules(BulkOperation bulkOperation, BulkOperationRuleCollection ruleCollection) { + ruleRepository.deleteAllByBulkOperationId(bulkOperation.getId()); + marcRuleRepository.deleteAllByBulkOperationId(bulkOperation.getId()); ruleCollection.getBulkOperationRules().forEach(bulkOperationRule -> { var rule = ruleRepository.save(org.folio.bulkops.domain.entity.BulkOperationRule.builder() @@ -59,9 +54,6 @@ public BulkOperationRuleCollection getRules(UUID bulkOperationId) { var rules = ruleRepository.findAllByBulkOperationId(bulkOperationId).stream() .map(this::mapBulkOperationRuleToDto) .toList(); - if (rules.isEmpty()) { - throw new NotFoundException("Bulk operation rules were not found by bulk operation id=" + bulkOperationId); - } return new BulkOperationRuleCollection().bulkOperationRules(rules).totalRecords(rules.size()); } @@ -83,11 +75,8 @@ private BulkOperationRule mapBulkOperationRuleToDto(org.folio.bulkops.domain.ent } @Transactional - public BulkOperationMarcRuleCollection saveMarcRules(BulkOperationMarcRuleCollection ruleCollection) { - ruleCollection.getBulkOperationMarcRules().stream() - .map(BulkOperationMarcRule::getBulkOperationId) - .distinct() - .forEach(marcRuleRepository::deleteAllByBulkOperationId); + public BulkOperationMarcRuleCollection saveMarcRules(BulkOperation bulkOperation, BulkOperationMarcRuleCollection ruleCollection) { + marcRuleRepository.deleteAllByBulkOperationId(bulkOperation.getId()); ruleCollection.getBulkOperationMarcRules() .forEach(marcRule -> marcRuleRepository.save(marcRulesMapper.mapToEntity(marcRule))); @@ -99,9 +88,6 @@ public BulkOperationMarcRuleCollection getMarcRules(UUID bulkOperationId) { var rules = marcRuleRepository.findAllByBulkOperationId(bulkOperationId).stream() .map(marcRulesMapper::mapToDto) .toList(); - if (rules.isEmpty()) { - throw new NotFoundException("Bulk operation MARC rules were not found by bulk operation id=" + bulkOperationId); - } return new BulkOperationMarcRuleCollection().bulkOperationMarcRules(rules).totalRecords(rules.size()); } } diff --git a/src/main/java/org/folio/bulkops/util/UpdateOptionTypeToFieldResolver.java b/src/main/java/org/folio/bulkops/util/UpdateOptionTypeToFieldResolver.java index 82e1a205e..8085c74f7 100644 --- a/src/main/java/org/folio/bulkops/util/UpdateOptionTypeToFieldResolver.java +++ b/src/main/java/org/folio/bulkops/util/UpdateOptionTypeToFieldResolver.java @@ -1,6 +1,7 @@ package org.folio.bulkops.util; import static org.folio.bulkops.domain.dto.EntityType.INSTANCE; +import static org.folio.bulkops.domain.dto.EntityType.INSTANCE_MARC; import static org.folio.bulkops.domain.dto.EntityType.USER; import static org.folio.bulkops.domain.dto.UpdateOptionType.ADMINISTRATIVE_NOTE; import static org.folio.bulkops.domain.dto.UpdateOptionType.CHECK_IN_NOTE; @@ -60,7 +61,7 @@ public static String getFieldByUpdateOptionType(UpdateOptionType type, EntityTyp return "Status"; } else if (SUPPRESS_FROM_DISCOVERY == type && entity != USER) { return "Suppress from discovery"; - } else if (STAFF_SUPPRESS == type && INSTANCE == entity) { + } else if (STAFF_SUPPRESS == type && Set.of(INSTANCE, INSTANCE_MARC).contains(entity)) { return "Staff suppress"; } else if (ITEM_NOTE == type) { return "Notes"; diff --git a/src/main/resources/db/changelog/changelog-master.xml b/src/main/resources/db/changelog/changelog-master.xml index 3a2c6e497..6e5868265 100644 --- a/src/main/resources/db/changelog/changelog-master.xml +++ b/src/main/resources/db/changelog/changelog-master.xml @@ -38,4 +38,5 @@ + diff --git a/src/main/resources/db/changelog/changes/11-01-2025_restore_id_column_bulk_operation_data_processing.sql b/src/main/resources/db/changelog/changes/11-01-2025_restore_id_column_bulk_operation_data_processing.sql new file mode 100644 index 000000000..be8f391a4 --- /dev/null +++ b/src/main/resources/db/changelog/changes/11-01-2025_restore_id_column_bulk_operation_data_processing.sql @@ -0,0 +1,10 @@ +TRUNCATE TABLE bulk_operation_data_processing; + +ALTER TABLE bulk_operation_data_processing +ADD COLUMN IF NOT EXISTS id uuid; + +ALTER TABLE bulk_operation_data_processing +DROP CONSTRAINT bulk_operation_data_processing_pkey; + +ALTER TABLE bulk_operation_data_processing +ADD CONSTRAINT bulk_operation_data_processing_pkey PRIMARY KEY (id); diff --git a/src/main/resources/db/changelog/changes/11-01-2025_restore_id_column_bulk_operation_data_processing.xml b/src/main/resources/db/changelog/changes/11-01-2025_restore_id_column_bulk_operation_data_processing.xml new file mode 100644 index 000000000..164d92486 --- /dev/null +++ b/src/main/resources/db/changelog/changes/11-01-2025_restore_id_column_bulk_operation_data_processing.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/src/main/resources/swagger.api/schemas/bulk_operation_marc_rule_collection.json b/src/main/resources/swagger.api/schemas/bulk_operation_marc_rule_collection.json index 70f0f1e0b..ff85ea558 100644 --- a/src/main/resources/swagger.api/schemas/bulk_operation_marc_rule_collection.json +++ b/src/main/resources/swagger.api/schemas/bulk_operation_marc_rule_collection.json @@ -9,8 +9,7 @@ "type": "array", "items": { "$ref": "bulk_operation_marc_rule.json#/BulkOperationMarcRule" - }, - "minItems": 1 + } }, "totalRecords": { "type": "integer" diff --git a/src/main/resources/swagger.api/schemas/bulk_operation_rule_collection.json b/src/main/resources/swagger.api/schemas/bulk_operation_rule_collection.json index 316eb0d61..64aba1e05 100644 --- a/src/main/resources/swagger.api/schemas/bulk_operation_rule_collection.json +++ b/src/main/resources/swagger.api/schemas/bulk_operation_rule_collection.json @@ -9,8 +9,7 @@ "type": "array", "items": { "$ref": "bulk_operation_rule.json#/BulkOperationRule" - }, - "minItems": 1 + } }, "totalRecords": { "type": "integer" diff --git a/src/main/resources/swagger.api/schemas/file_content_type.json b/src/main/resources/swagger.api/schemas/file_content_type.json index a4e8f93e2..d8c18c054 100644 --- a/src/main/resources/swagger.api/schemas/file_content_type.json +++ b/src/main/resources/swagger.api/schemas/file_content_type.json @@ -8,6 +8,7 @@ "MATCHED_RECORDS_FILE", "RECORD_MATCHING_ERROR_FILE", "PROPOSED_CHANGES_FILE", + "PROPOSED_CHANGES_MARC_FILE", "COMMITTED_RECORDS_FILE", "COMMITTING_CHANGES_ERROR_FILE" ] diff --git a/src/test/java/org/folio/bulkops/controller/BulkOperationControllerTest.java b/src/test/java/org/folio/bulkops/controller/BulkOperationControllerTest.java index 06153e7a4..4cfb60e00 100644 --- a/src/test/java/org/folio/bulkops/controller/BulkOperationControllerTest.java +++ b/src/test/java/org/folio/bulkops/controller/BulkOperationControllerTest.java @@ -11,6 +11,7 @@ import static org.folio.bulkops.domain.dto.FileContentType.COMMITTING_CHANGES_ERROR_FILE; import static org.folio.bulkops.domain.dto.FileContentType.MATCHED_RECORDS_FILE; import static org.folio.bulkops.domain.dto.FileContentType.PROPOSED_CHANGES_FILE; +import static org.folio.bulkops.domain.dto.FileContentType.PROPOSED_CHANGES_MARC_FILE; import static org.folio.bulkops.domain.dto.FileContentType.RECORD_MATCHING_ERROR_FILE; import static org.folio.bulkops.domain.dto.FileContentType.TRIGGERING_FILE; import static org.folio.bulkops.domain.dto.IdentifierType.BARCODE; @@ -22,6 +23,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -119,7 +121,7 @@ void shouldChangeEntityTypeAndClearProcessingOnPostContentUpdates() { } """; when(bulkOperationService.getBulkOperationOrThrow(bulkOperation.getId())).thenReturn(bulkOperation); - when(ruleService.saveRules(any(BulkOperationRuleCollection.class))) + when(ruleService.saveRules(eq(bulkOperation), any(BulkOperationRuleCollection.class))) .thenReturn(new BulkOperationRuleCollection().bulkOperationRules(Collections.emptyList()).totalRecords(1)); try (var context = new FolioExecutionContextSetter(folioExecutionContext)) { @@ -158,7 +160,7 @@ void shouldDownloadFileWithPreview(FileContentType type, org.folio.bulkops.domai .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); - if (PROPOSED_CHANGES_FILE.equals(type) && INSTANCE_MARC.equals(entityType)) { + if (PROPOSED_CHANGES_MARC_FILE.equals(type) && INSTANCE_MARC.equals(entityType)) { verify(remoteFileSystemClient).get("G"); } } @@ -195,7 +197,7 @@ void shouldAddUtf8BomToDownloadedCSV(FileContentType fileContentType, org.folio. .andExpect(status().isOk()).andReturn(); var actual = result.getResponse().getContentAsByteArray(); - if (fileContentType == PROPOSED_CHANGES_FILE && entityType == INSTANCE_MARC) { + if (fileContentType == PROPOSED_CHANGES_MARC_FILE && entityType == INSTANCE_MARC) { assertNotEquals(content.getBytes().length + utf8bom.length, actual.length); } else { assertEquals(content.getBytes().length + utf8bom.length, actual.length); @@ -327,7 +329,7 @@ void shouldPostBulkOperationMarcRules() { .content(content)) .andExpect(status().isOk()); - verify(ruleService).saveMarcRules(any(BulkOperationMarcRuleCollection.class)); + verify(ruleService).saveMarcRules(eq(bulkOperation), any(BulkOperationMarcRuleCollection.class)); verify(bulkOperationService).clearOperationProcessing(bulkOperation); } @@ -369,7 +371,7 @@ private static Stream fileContentTypeToEntityTypeCollection() { Arguments.of(PROPOSED_CHANGES_FILE, HOLDINGS_RECORD), Arguments.of(PROPOSED_CHANGES_FILE, USER), Arguments.of(PROPOSED_CHANGES_FILE, INSTANCE), - Arguments.of(PROPOSED_CHANGES_FILE, INSTANCE_MARC), + Arguments.of(PROPOSED_CHANGES_MARC_FILE, INSTANCE_MARC), Arguments.of(COMMITTED_RECORDS_FILE, ITEM), Arguments.of(COMMITTED_RECORDS_FILE, HOLDINGS_RECORD), Arguments.of(COMMITTED_RECORDS_FILE, USER), diff --git a/src/test/java/org/folio/bulkops/processor/marc/MarcInstanceDataProcessorTest.java b/src/test/java/org/folio/bulkops/processor/marc/MarcInstanceDataProcessorTest.java index a784a5854..fada85bc0 100644 --- a/src/test/java/org/folio/bulkops/processor/marc/MarcInstanceDataProcessorTest.java +++ b/src/test/java/org/folio/bulkops/processor/marc/MarcInstanceDataProcessorTest.java @@ -671,7 +671,7 @@ void shouldSaveErrorOnRuleValidationException() { var findAndAppendRule = new BulkOperationMarcRule() .bulkOperationId(bulkOperationId) - .tag("600") + .tag("001") .ind1("1") .ind2("\\") .subfield("b") @@ -696,7 +696,7 @@ void shouldSaveErrorOnRuleValidationException() { processor.update(operation, marcRecord, rules, date); - var expectedErrorMessage = "Bulk edit of 600 field is not supported"; + var expectedErrorMessage = "Bulk edit of 001 field is not supported"; verify(errorService).saveError(bulkOperationId, identifier, expectedErrorMessage); } } diff --git a/src/test/java/org/folio/bulkops/repository/BulkOperationDataProcessingRepositoryTest.java b/src/test/java/org/folio/bulkops/repository/BulkOperationDataProcessingRepositoryTest.java index 1a97646e9..508fc3f00 100644 --- a/src/test/java/org/folio/bulkops/repository/BulkOperationDataProcessingRepositoryTest.java +++ b/src/test/java/org/folio/bulkops/repository/BulkOperationDataProcessingRepositoryTest.java @@ -37,7 +37,7 @@ void shouldSaveEntity() { void shouldFindEntityById() { try (var context = new FolioExecutionContextSetter(folioExecutionContext)) { var created = repository.save(createEntity()); - var retrieved = repository.findById(created.getBulkOperationId()); + var retrieved = repository.findById(created.getId()); assertTrue(retrieved.isPresent() && created.getBulkOperationId().equals(retrieved.get().getBulkOperationId())); } } diff --git a/src/test/java/org/folio/bulkops/service/BulkOperationServiceTest.java b/src/test/java/org/folio/bulkops/service/BulkOperationServiceTest.java index ddccad14f..3c5b65c82 100644 --- a/src/test/java/org/folio/bulkops/service/BulkOperationServiceTest.java +++ b/src/test/java/org/folio/bulkops/service/BulkOperationServiceTest.java @@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.times; @@ -250,7 +251,7 @@ void shouldUploadManualInstances() { when(bulkOperationRepository.findById(operationId)) .thenReturn(Optional.of(BulkOperation.builder().id(operationId).linkToTriggeringCsvFile("path/barcodes.csv").status(DATA_MODIFICATION).build())); - var linkToPreviewFile = operationId + "/" + LocalDate.now() + "-Updates-Preview-barcodes.csv"; + var linkToPreviewFile = operationId + "/" + LocalDate.now() + "-Updates-Preview-CSV-barcodes.csv"; when(remoteFileSystemClient.put(any(InputStream.class), eq(linkToPreviewFile))) .thenReturn(linkToPreviewFile); @@ -372,7 +373,7 @@ void shouldConfirmChanges(ApproachType approach) { var pathToOrigin = "path/origin.json"; var pathToModified = bulkOperationId + "/json/" + LocalDate.now() + "-Updates-Preview-identifiers.json"; var pathToOriginalCsv = bulkOperationId + "/origin.csv"; - var pathToModifiedCsv = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-identifiers.csv"; + var pathToModifiedCsv = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-CSV-identifiers.csv"; var pathToUserJson = "src/test/resources/files/user.json"; when(consortiaService.isTenantCentral(any())).thenReturn(false); @@ -400,12 +401,24 @@ void shouldConfirmChanges(ApproachType approach) { .type(UpdateActionType.REPLACE_WITH) .updated(newPatronGroupId)))))) .totalRecords(1)); + when(ruleService.getMarcRules(bulkOperationId)) + .thenReturn(new BulkOperationMarcRuleCollection() + .bulkOperationMarcRules(Collections.emptyList()) + .totalRecords(0)); when(dataProcessingRepository.save(any(BulkOperationDataProcessing.class))) .thenReturn(BulkOperationDataProcessing.builder() + .bulkOperationId(bulkOperationId) .processedNumOfRecords(0) .build()); + when(dataProcessingRepository.findAllByBulkOperationId(bulkOperationId)) + .thenReturn(Collections.singletonList(BulkOperationDataProcessing.builder() + .bulkOperationId(bulkOperationId) + .status(StatusType.COMPLETED) + .processedNumOfRecords(1) + .build())); + when(remoteFileSystemClient.get(pathToOrigin)) .thenReturn(new FileInputStream(pathToUserJson)); @@ -421,7 +434,7 @@ void shouldConfirmChanges(ApproachType approach) { bulkOperationService.startBulkOperation(bulkOperationId, UUID.randomUUID(), new BulkOperationStart().approach(approach).step(EDIT)); - var expectedPathToModifiedCsvFile = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-identifiers.csv"; + var expectedPathToModifiedCsvFile = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-CSV-identifiers.csv"; var streamCaptor = ArgumentCaptor.forClass(InputStream.class); var pathCaptor = ArgumentCaptor.forClass(String.class); Awaitility.await().untilAsserted(() -> verify(remoteFolioS3Client, times(2)).write(pathCaptor.capture(), streamCaptor.capture())); @@ -437,7 +450,7 @@ void shouldConfirmChanges(ApproachType approach) { assertThat(capturedDataProcessingEntity.getEndTime(), notNullValue()); var bulkOperationCaptor = ArgumentCaptor.forClass(BulkOperation.class); - Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(3)).save(bulkOperationCaptor.capture())); + Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(5)).save(bulkOperationCaptor.capture())); var capturedBulkOperation = bulkOperationCaptor.getValue(); assertThat(capturedBulkOperation.getLinkToModifiedRecordsCsvFile(), equalTo(expectedPathToModifiedCsvFile)); assertThat(capturedBulkOperation.getStatus(), equalTo(OperationStatusType.REVIEW_CHANGES)); @@ -482,8 +495,14 @@ void shouldPopulateErrorToBulkOperationIfS3IssuesForConfirmChanges() { .updated(newPatronGroupId)))))) .totalRecords(1)); + when(ruleService.getMarcRules(bulkOperationId)) + .thenReturn(new BulkOperationMarcRuleCollection() + .bulkOperationMarcRules(Collections.emptyList()) + .totalRecords(0)); + when(dataProcessingRepository.save(any(BulkOperationDataProcessing.class))) .thenReturn(BulkOperationDataProcessing.builder() + .bulkOperationId(bulkOperationId) .processedNumOfRecords(0) .build()); @@ -496,7 +515,7 @@ void shouldPopulateErrorToBulkOperationIfS3IssuesForConfirmChanges() { bulkOperationService.startBulkOperation(bulkOperationId, UUID.randomUUID(), new BulkOperationStart().approach(ApproachType.IN_APP).step(EDIT)); var bulkOperationCaptor = ArgumentCaptor.forClass(BulkOperation.class); - Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(3)).save(bulkOperationCaptor.capture())); + Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(4)).save(bulkOperationCaptor.capture())); var capturedBulkOperation = bulkOperationCaptor.getValue(); assertThat(capturedBulkOperation.getStatus(), equalTo(OperationStatusType.FAILED)); @@ -514,7 +533,7 @@ void shouldConfirmChangesForInstanceMarc() { var bulkOperationMarcRule = new BulkOperationMarcRule(); bulkOperationMarcRule.setBulkOperationId(bulkOperationId); bulkOperationMarcRule.setActions(List.of(marcAction)); - bulkOperationMarcRule.setTag("tag"); + bulkOperationMarcRule.setTag("500"); bulkOperationMarcRule.setInd1("ind1"); bulkOperationMarcRule.setInd2("ind2"); @@ -523,10 +542,11 @@ void shouldConfirmChangesForInstanceMarc() { var pathToTriggering = "/some/path/instance_marc.csv"; var pathToMatchedRecordsMarcFile = "/some/path/Marc-Records-instance_marc.mrc"; - var pathToOriginalCsv = bulkOperationId + "/origin.csv"; + var pathToMatchedJson = bulkOperationId + "/instance_marc.json"; var pathToModifiedRecordsMarcFileName= "Updates-Preview-Marc-Records-instance_marc.mrc"; var pathToInstanceMarc = "src/test/resources/files/instance_marc.mrc"; - var expectedPathToModifiedMarcFile = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-instance_marc.mrc"; + var pathToInstanceJson = "src/test/resources/files/instance_marc.json"; + var expectedPathToModifiedMarcFile = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-MARC-instance_marc.mrc"; when(bulkOperationRepository.findById(any(UUID.class))) .thenReturn(Optional.of(BulkOperation.builder() @@ -535,19 +555,34 @@ void shouldConfirmChangesForInstanceMarc() { .entityType(EntityType.INSTANCE_MARC) .identifierType(IdentifierType.ID) .linkToTriggeringCsvFile(pathToTriggering) - .linkToMatchedRecordsCsvFile(pathToOriginalCsv) + .linkToMatchedRecordsJsonFile(pathToMatchedJson) .linkToMatchedRecordsMarcFile(pathToMatchedRecordsMarcFile) .linkToModifiedRecordsMarcFile(pathToModifiedRecordsMarcFileName) .processedNumOfRecords(0) .build())); when(ruleService.getMarcRules(bulkOperationId)) .thenReturn(bulkOperationMarcRuleCollection); + when(ruleService.getRules(bulkOperationId)) + .thenReturn(new BulkOperationRuleCollection() + .bulkOperationRules(Collections.emptyList()) + .totalRecords(0)); when(dataProcessingRepository.save(any(BulkOperationDataProcessing.class))) .thenReturn(BulkOperationDataProcessing.builder() + .bulkOperationId(bulkOperationId) .processedNumOfRecords(0) .build()); - when(remoteFileSystemClient.get(pathToMatchedRecordsMarcFile )) + when(dataProcessingRepository.findAllByBulkOperationId(bulkOperationId)) + .thenReturn(Collections.singletonList(BulkOperationDataProcessing.builder() + .bulkOperationId(bulkOperationId) + .status(StatusType.COMPLETED) + .processedNumOfRecords(1) + .build())); + when(remoteFileSystemClient.get(pathToMatchedRecordsMarcFile)) .thenReturn(new FileInputStream(pathToInstanceMarc)); + when(remoteFileSystemClient.get(pathToMatchedJson)) + .thenReturn(new FileInputStream(pathToInstanceJson)); + when(remoteFileSystemClient.writer(anyString())) + .thenReturn(new StringWriter()); when(remoteFileSystemClient.marcWriter(expectedPathToModifiedMarcFile)).thenReturn(new MarcRemoteStorageWriter(new RemoteStorageWriter(expectedPathToModifiedMarcFile, 8192, remoteFolioS3Client))); bulkOperationService.startBulkOperation(bulkOperationId, UUID.randomUUID(), new BulkOperationStart().approach(ApproachType.IN_APP).step(EDIT)); @@ -558,14 +593,14 @@ void shouldConfirmChangesForInstanceMarc() { Awaitility.await().untilAsserted(() -> verify(remoteFolioS3Client, times(1)).write(pathCaptor.capture(), streamCaptor.capture())); var dataProcessingCaptor = ArgumentCaptor.forClass(BulkOperationDataProcessing.class); - Awaitility.await().untilAsserted(() -> verify(dataProcessingRepository, times(2)).save(dataProcessingCaptor.capture())); - var capturedDataProcessingEntity = dataProcessingCaptor.getAllValues().get(1); + Awaitility.await().untilAsserted(() -> verify(dataProcessingRepository, times(4)).save(dataProcessingCaptor.capture())); + var capturedDataProcessingEntity = dataProcessingCaptor.getAllValues().get(2); assertThat(capturedDataProcessingEntity.getProcessedNumOfRecords(), is(1)); assertThat(capturedDataProcessingEntity.getStatus(), equalTo(StatusType.COMPLETED)); assertThat(capturedDataProcessingEntity.getEndTime(), notNullValue()); var bulkOperationCaptor = ArgumentCaptor.forClass(BulkOperation.class); - Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(3)).save(bulkOperationCaptor.capture())); + Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(8)).save(bulkOperationCaptor.capture())); var capturedBulkOperation = bulkOperationCaptor.getValue(); assertThat(capturedBulkOperation.getLinkToModifiedRecordsMarcFile(), equalTo(expectedPathToModifiedMarcFile)); assertThat(capturedBulkOperation.getStatus(), equalTo(OperationStatusType.REVIEW_CHANGES)); @@ -591,6 +626,8 @@ void shouldPopulateErrorToBulkOperationIfS3IssuesForConfirmChangesForInstanceMa var pathToTriggering = "/some/path/instance_marc.csv"; var pathToMatchedRecordsMarcFile = "/some/path/Marc-Records-instance_marc.mrc"; + var pathToMatchedRecordsJsonFile = "/some/path/Marc-Records-instance_marc.json"; + var pathToInstanceJson = "src/test/resources/files/instance_marc.json"; var pathToOriginalCsv = bulkOperationId + "/origin.csv"; var pathToModifiedRecordsMarcFileName= "Updates-Preview-Marc-Records-instance_marc.mrc"; var expectedPathToModifiedMarcFile = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-Marc-Records-instance_marc.mrc"; @@ -603,16 +640,26 @@ void shouldPopulateErrorToBulkOperationIfS3IssuesForConfirmChangesForInstanceMa .identifierType(IdentifierType.ID) .linkToTriggeringCsvFile(pathToTriggering) .linkToMatchedRecordsCsvFile(pathToOriginalCsv) + .linkToMatchedRecordsJsonFile(pathToMatchedRecordsJsonFile) .linkToMatchedRecordsMarcFile(pathToMatchedRecordsMarcFile) .linkToModifiedRecordsMarcFile(pathToModifiedRecordsMarcFileName) .processedNumOfRecords(0) .build())); when(ruleService.getMarcRules(bulkOperationId)) .thenReturn(bulkOperationMarcRuleCollection); + when(ruleService.getRules(bulkOperationId)) + .thenReturn(new BulkOperationRuleCollection() + .bulkOperationRules(Collections.emptyList()) + .totalRecords(0)); when(dataProcessingRepository.save(any(BulkOperationDataProcessing.class))) .thenReturn(BulkOperationDataProcessing.builder() + .bulkOperationId(bulkOperationId) .processedNumOfRecords(0) .build()); + when(remoteFileSystemClient.get(pathToMatchedRecordsJsonFile)) + .thenReturn(new FileInputStream(pathToInstanceJson)); + when(remoteFileSystemClient.writer(anyString())) + .thenReturn(new StringWriter()); when(remoteFileSystemClient.get(pathToMatchedRecordsMarcFile)) .thenThrow(new S3ClientException("error")); when(remoteFileSystemClient.marcWriter(expectedPathToModifiedMarcFile)).thenReturn(new MarcRemoteStorageWriter(new RemoteStorageWriter(expectedPathToModifiedMarcFile, 8192, remoteFolioS3Client))); @@ -620,7 +667,7 @@ void shouldPopulateErrorToBulkOperationIfS3IssuesForConfirmChangesForInstanceMa bulkOperationService.startBulkOperation(bulkOperationId, UUID.randomUUID(), new BulkOperationStart().approach(ApproachType.IN_APP).step(EDIT)); var bulkOperationCaptor = ArgumentCaptor.forClass(BulkOperation.class); - Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(3)).save(bulkOperationCaptor.capture())); + Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, atLeast(6)).save(bulkOperationCaptor.capture())); var capturedBulkOperation = bulkOperationCaptor.getValue(); assertThat(capturedBulkOperation.getStatus(), equalTo(OperationStatusType.FAILED)); assertThat(capturedBulkOperation.getErrorMessage(),equalTo(format(ERROR_MESSAGE_PATTERN, ErrorCode.ERROR_NOT_CONFIRM_CHANGES_S3_ISSUE, "error"))); @@ -646,9 +693,11 @@ void shouldFailConfirmChangesForInstanceMarcIfMarcWriterNotAvailable() { var pathToTriggering = "/some/path/instance_marc.csv"; var pathToMatchedRecordsMarcFile = "/some/path/Marc-Records-instance_marc.mrc"; - var pathToOriginalCsv = bulkOperationId + "/origin.csv"; + var pathToMatchedRecordsJsonFile = "/some/path/Marc-Records-instance_marc.json"; + var pathToOriginalJson = bulkOperationId + "/instance_marc.json"; var pathToModifiedRecordsMarcFileName= "Updates-Preview-Marc-Records-instance_marc.mrc"; var pathToInstanceMarc = "src/test/resources/files/instance_marc.mrc"; + var pathToInstanceJson = "src/test/resources/files/instance_marc.json"; var expectedPathToModifiedMarcFile = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-Marc-Records-instance_marc.mrc"; when(bulkOperationRepository.findById(any(UUID.class))) @@ -658,28 +707,33 @@ void shouldFailConfirmChangesForInstanceMarcIfMarcWriterNotAvailable() { .entityType(EntityType.INSTANCE_MARC) .identifierType(IdentifierType.ID) .linkToTriggeringCsvFile(pathToTriggering) - .linkToMatchedRecordsCsvFile(pathToOriginalCsv) + .linkToMatchedRecordsCsvFile(pathToOriginalJson) .linkToMatchedRecordsMarcFile(pathToMatchedRecordsMarcFile) + .linkToMatchedRecordsJsonFile(pathToMatchedRecordsJsonFile) .linkToModifiedRecordsMarcFile(pathToModifiedRecordsMarcFileName) .processedNumOfRecords(0) .build())); when(ruleService.getMarcRules(bulkOperationId)) .thenReturn(bulkOperationMarcRuleCollection); + when(ruleService.getRules(bulkOperationId)) + .thenReturn(new BulkOperationRuleCollection().bulkOperationRules(Collections.emptyList()).totalRecords(0)); when(dataProcessingRepository.save(any(BulkOperationDataProcessing.class))) .thenReturn(BulkOperationDataProcessing.builder() + .bulkOperationId(bulkOperationId) .processedNumOfRecords(0) .build()); - when(remoteFileSystemClient.get(pathToMatchedRecordsMarcFile )) + when(remoteFileSystemClient.get(pathToMatchedRecordsJsonFile)) + .thenReturn(new FileInputStream(pathToInstanceJson)); + when(remoteFileSystemClient.writer(anyString())) + .thenReturn(new StringWriter()); + when(remoteFileSystemClient.get(pathToMatchedRecordsMarcFile)) .thenReturn(new FileInputStream(pathToInstanceMarc)); when(remoteFileSystemClient.marcWriter(expectedPathToModifiedMarcFile)).thenThrow(new RuntimeException("error")); bulkOperationService.startBulkOperation(bulkOperationId, UUID.randomUUID(), new BulkOperationStart().approach(ApproachType.IN_APP).step(EDIT)); - var dataProcessingCaptor = ArgumentCaptor.forClass(BulkOperationDataProcessing.class); - Awaitility.await().untilAsserted(() -> verify(dataProcessingRepository, times(2)).save(dataProcessingCaptor.capture())); - var bulkOperationCaptor = ArgumentCaptor.forClass(BulkOperation.class); - Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(3)).save(bulkOperationCaptor.capture())); + Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(7)).save(bulkOperationCaptor.capture())); var capturedBulkOperation = bulkOperationCaptor.getValue(); assertThat(capturedBulkOperation.getStatus(), equalTo(OperationStatusType.FAILED)); } @@ -694,7 +748,7 @@ void shouldConfirmChangesForItemWhenValidationErrorAndOtherValidChangesExist(App var pathToOrigin = "path/origin.json"; var pathToModified = bulkOperationId + "/json/" + LocalDate.now() + "-Updates-Preview-identifiers.json"; var pathToOriginalCsv = bulkOperationId + "/origin.csv"; - var pathToModifiedCsv = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-identifiers.csv"; + var pathToModifiedCsv = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-CSV-identifiers.csv"; var pathToItemJson = "src/test/resources/files/item.json"; mockHoldingsClient(); @@ -714,9 +768,6 @@ void shouldConfirmChangesForItemWhenValidationErrorAndOtherValidChangesExist(App .linkToMatchedRecordsCsvFile(pathToOriginalCsv) .processedNumOfRecords(0) .committedNumOfErrors(0) - .build()), Optional.of(BulkOperation.builder() - .id(bulkOperationId) - .committedNumOfErrors(1) .build())); var tempLocationRules = new BulkOperationRule() @@ -741,12 +792,24 @@ void shouldConfirmChangesForItemWhenValidationErrorAndOtherValidChangesExist(App .thenReturn(new BulkOperationRuleCollection() .bulkOperationRules(List.of(tempLocationRules, statusRules)) .totalRecords(2)); + when(ruleService.getMarcRules(bulkOperationId)) + .thenReturn(new BulkOperationMarcRuleCollection() + .bulkOperationMarcRules(Collections.emptyList()) + .totalRecords(0)); when(dataProcessingRepository.save(any(BulkOperationDataProcessing.class))) .thenReturn(BulkOperationDataProcessing.builder() + .bulkOperationId(bulkOperationId) .processedNumOfRecords(0) .build()); + when(dataProcessingRepository.findAllByBulkOperationId(bulkOperationId)) + .thenReturn(Collections.singletonList(BulkOperationDataProcessing.builder() + .bulkOperationId(bulkOperationId) + .status(StatusType.COMPLETED) + .processedNumOfRecords(1) + .build())); + when(remoteFileSystemClient.get(pathToOrigin)) .thenReturn(new FileInputStream(pathToItemJson)); @@ -758,7 +821,7 @@ void shouldConfirmChangesForItemWhenValidationErrorAndOtherValidChangesExist(App bulkOperationService.startBulkOperation(bulkOperationId, UUID.randomUUID(), new BulkOperationStart().approach(approach).step(EDIT)); - var expectedPathToModifiedCsvFile = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-identifiers.csv"; + var expectedPathToModifiedCsvFile = bulkOperationId + "/" + LocalDate.now() + "-Updates-Preview-CSV-identifiers.csv"; var streamCaptor = ArgumentCaptor.forClass(InputStream.class); var pathCaptor = ArgumentCaptor.forClass(String.class); @@ -776,10 +839,9 @@ void shouldConfirmChangesForItemWhenValidationErrorAndOtherValidChangesExist(App verify(errorService).saveError(eq(bulkOperationId), eq("10101"), any(String.class)); var bulkOperationCaptor = ArgumentCaptor.forClass(BulkOperation.class); - Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(3)).save(bulkOperationCaptor.capture())); + Awaitility.await().untilAsserted(() -> verify(bulkOperationRepository, times(5)).save(bulkOperationCaptor.capture())); var capturedBulkOperation = bulkOperationCaptor.getValue(); assertThat(capturedBulkOperation.getLinkToModifiedRecordsCsvFile(), equalTo(expectedPathToModifiedCsvFile)); - assertThat(capturedBulkOperation.getCommittedNumOfErrors(), equalTo(1)); assertThat(capturedBulkOperation.getProcessedNumOfRecords(), equalTo(1)); assertThat(capturedBulkOperation.getStatus(), equalTo(OperationStatusType.REVIEW_CHANGES)); } @@ -819,29 +881,32 @@ void shouldUpdateStatusesWhenConfirmChangesFails() { when(bulkOperationRepository.findById(any(UUID.class))) .thenReturn(Optional.of(operation)); - when(ruleService.getRules(bulkOperationId)) - .thenReturn(new BulkOperationRuleCollection() + var rules = new BulkOperationRuleCollection() .bulkOperationRules(List.of(new BulkOperationRule() .ruleDetails(new BulkOperationRuleRuleDetails() .option(UpdateOptionType.PATRON_GROUP) .actions(List.of(new Action() .type(UpdateActionType.REPLACE_WITH) .updated(newPatronGroupId)))))) - .totalRecords(1)); + .totalRecords(1); + when(ruleService.getRules(bulkOperationId)).thenReturn(rules); + + var dataProcessing = BulkOperationDataProcessing.builder() + .bulkOperationId(bulkOperationId) + .processedNumOfRecords(0) + .build(); when(dataProcessingRepository.save(any(BulkOperationDataProcessing.class))) - .thenReturn(BulkOperationDataProcessing.builder() - .processedNumOfRecords(0) - .build()); + .thenReturn(dataProcessing); when(remoteFileSystemClient.get(pathToOrigin)) .thenThrow(new RuntimeException("Failed to read file")); - bulkOperationService.confirm(operation); + bulkOperationService.confirm(dataProcessing); var dataProcessingCaptor = ArgumentCaptor.forClass(BulkOperationDataProcessing.class); - Awaitility.await().untilAsserted(() -> verify(dataProcessingRepository, times(2)).save(dataProcessingCaptor.capture())); - var capturedDataProcessingEntity = dataProcessingCaptor.getAllValues().get(1); + Awaitility.await().untilAsserted(() -> verify(dataProcessingRepository).save(dataProcessingCaptor.capture())); + var capturedDataProcessingEntity = dataProcessingCaptor.getAllValues().get(0); assertThat(capturedDataProcessingEntity.getStatus(), equalTo(StatusType.FAILED)); assertThat(capturedDataProcessingEntity.getEndTime(), notNullValue()); @@ -1258,7 +1323,7 @@ void clearOperationProcessing() { bulkOperationService.clearOperationProcessing(operation); - verify(dataProcessingRepository).deleteById(any(UUID.class)); + verify(dataProcessingRepository).deleteAllByBulkOperationId(any(UUID.class)); verify(bulkOperationRepository).save(any(BulkOperation.class)); } diff --git a/src/test/java/org/folio/bulkops/service/PreviewServiceTest.java b/src/test/java/org/folio/bulkops/service/PreviewServiceTest.java index a24a76dec..292598fbf 100644 --- a/src/test/java/org/folio/bulkops/service/PreviewServiceTest.java +++ b/src/test/java/org/folio/bulkops/service/PreviewServiceTest.java @@ -443,6 +443,10 @@ void shouldGetCompositePreviewOnEditStepForMarcInstance() { .totalRecords(1); when(ruleService.getMarcRules(bulkOperationId)).thenReturn(rules); + when(ruleService.getRules(bulkOperationId)) + .thenReturn(new BulkOperationRuleCollection() + .bulkOperationRules(Collections.emptyList()) + .totalRecords(0)); when(instanceNoteTypesClient.getNoteTypeById(summaryNoteTypeId)) .thenReturn(new InstanceNoteType().name("Summary")); when(instanceReferenceService.getAllInstanceNoteTypes()) @@ -538,6 +542,10 @@ void shouldGetCompositePreviewOnEditStepForFolioAndMarcInstance() { .totalRecords(1); when(ruleService.getMarcRules(bulkOperationId)).thenReturn(rules); + when(ruleService.getRules(bulkOperationId)) + .thenReturn(new BulkOperationRuleCollection() + .bulkOperationRules(Collections.emptyList()) + .totalRecords(0)); when(instanceNoteTypesClient.getNoteTypeById(summaryNoteTypeId)) .thenReturn(new InstanceNoteType().name("Summary")); when(instanceReferenceService.getAllInstanceNoteTypes()) @@ -681,6 +689,10 @@ void shouldEnrichMarcPreviewWithAdministrativeDataOnCommitStepForFolioAndMarcIns .totalRecords(1); when(ruleService.getMarcRules(bulkOperationId)).thenReturn(rules); + when(ruleService.getRules(bulkOperationId)) + .thenReturn(new BulkOperationRuleCollection() + .bulkOperationRules(Collections.emptyList()) + .totalRecords(0)); when(instanceNoteTypesClient.getNoteTypeById(summaryNoteTypeId)) .thenReturn(new InstanceNoteType().name("Summary")); when(instanceReferenceService.getAllInstanceNoteTypes()) diff --git a/src/test/java/org/folio/bulkops/service/RuleServiceTest.java b/src/test/java/org/folio/bulkops/service/RuleServiceTest.java index 7fc07e59a..641ee927e 100644 --- a/src/test/java/org/folio/bulkops/service/RuleServiceTest.java +++ b/src/test/java/org/folio/bulkops/service/RuleServiceTest.java @@ -18,6 +18,7 @@ import org.folio.bulkops.domain.dto.BulkOperationMarcRuleCollection; import org.folio.bulkops.domain.dto.UpdateActionType; import org.folio.bulkops.domain.dto.UpdateOptionType; +import org.folio.bulkops.domain.entity.BulkOperation; import org.folio.bulkops.domain.entity.BulkOperationRuleDetails; import org.folio.bulkops.repository.BulkOperationMarcRuleRepository; import org.folio.bulkops.repository.BulkOperationRuleDetailsRepository; @@ -42,10 +43,11 @@ class RuleServiceTest extends BaseTest { @Test void shouldSaveRules() { try (var context = new FolioExecutionContextSetter(folioExecutionContext)) { + var operation = BulkOperation.builder().id(BULK_OPERATION_ID).build(); when(ruleRepository.save(any(org.folio.bulkops.domain.entity.BulkOperationRule.class))) .thenReturn(org.folio.bulkops.domain.entity.BulkOperationRule.builder().id(UUID.randomUUID()).build()); - ruleService.saveRules(rules()); + ruleService.saveRules(operation, rules()); verify(ruleRepository).deleteAllByBulkOperationId(BULK_OPERATION_ID); verify(ruleRepository).save(any(org.folio.bulkops.domain.entity.BulkOperationRule.class)); @@ -73,10 +75,11 @@ void shouldGetRules() { @Test void shouldSaveMarcRules() { try (var context = new FolioExecutionContextSetter(folioExecutionContext)) { + var operation = BulkOperation.builder().id(BULK_OPERATION_ID).build(); when(marcRuleRepository.save(any(org.folio.bulkops.domain.entity.BulkOperationMarcRule.class))) .thenReturn(org.folio.bulkops.domain.entity.BulkOperationMarcRule.builder().id(UUID.randomUUID()).build()); - ruleService.saveMarcRules(marcRules()); + ruleService.saveMarcRules(operation, marcRules()); verify(marcRuleRepository).deleteAllByBulkOperationId(BULK_OPERATION_ID); verify(marcRuleRepository).save(any(org.folio.bulkops.domain.entity.BulkOperationMarcRule.class)); diff --git a/src/test/resources/files/instance_marc.json b/src/test/resources/files/instance_marc.json new file mode 100644 index 000000000..38dbf7b55 --- /dev/null +++ b/src/test/resources/files/instance_marc.json @@ -0,0 +1,101 @@ +{ + "tenantId": "tenant1", + "entity": { + "id": "69640328-788e-43fc-9c3c-af39e243f3b7", + "_version": "81", + "hrid": "inst000000000001", + "source": "MARC", + "title": "ABA Journal", + "administrativeNotes": [ + "Sample note" + ], + "indexTitle": "Index title", + "parentInstances": [], + "childInstances": [], + "isBoundWith": false, + "alternativeTitles": [], + "editions": [ + "2021", + "2022" + ], + "series": [ + { + "authorityId": null, + "value": "series" + } + ], + "identifiers": [ + { + "identifierTypeId": "913300b2-03ed-469a-8179-c1092c991227", + "value": "0747-0088" + }, + { + "identifierTypeId": "c858e4f2-2b6b-4385-842b-60732ee14abb", + "value": "84641839" + } + ], + "contributors": [ + { + "authorityId": null, + "contributorNameTypeId": "2b94c631-fca9-4892-a730-03ee529ffe2a", + "name": "Sample contributor", + "contributorTypeId": null, + "contributorTypeText": "", + "primary": false + } + ], + "subjects": [], + "classifications": [], + "publication": [ + { + "publisher": "American Bar Association", + "place": "Chicago, Ill.", + "dateOfPublication": "1915-1983", + "role": null + } + ], + "publicationFrequency": [ + "freq1", + "freq2" + ], + "publicationRange": [ + "range1", + "range2" + ], + "electronicAccess": [], + "instanceTypeId": "6312d172-f0cf-40f6-b27d-9fa8feaf332f", + "instanceFormatIds": [ + "fe1b9adb-e0cf-4e05-905f-ce9986279404" + ], + "physicalDescriptions": [ + "Physical description1", + "Physical description2" + ], + "languages": [ + "eng", + "fre" + ], + "notes": [], + "modeOfIssuanceId": "068b5344-e2a6-40df-9186-1829e13cd344", + "catalogedDate": "2023-12-27", + "previouslyHeld": false, + "discoverySuppress": false, + "statisticalCodeIds": [], + "statusId": "2a340d34-6b70-443a-bb1b-1b8d1c65d862", + "statusUpdatedDate": "2023-12-27T10:57:11.903Z", + "metadata": { + "createdDate": "2023-11-10T11:54:16.279+00:00", + "createdByUserId": "cffb2565-07fc-470b-86c6-17d8ce14432e", + "updatedDate": "2023-12-27T11:01:48.248+00:00", + "updatedByUserId": "ca6022de-2644-46fe-b6f2-78df15483721" + }, + "tags": { + "tagList": [] + }, + "natureOfContentTermIds": [ + "44cd89f3-2e76-469f-a955-cc57cb9e0395" + ], + "precedingTitles": [], + "succeedingTitles": [] + } +}