Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MODBULKOPS-429 - Commit changes - MARC Bib records with administrative data #356

Merged
merged 9 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
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.FileContentType.COMMITTED_RECORDS_FILE;
import static org.folio.bulkops.domain.dto.FileContentType.COMMITTED_RECORDS_MARC_FILE;
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;
Expand Down Expand Up @@ -164,9 +165,9 @@ public ResponseEntity<Resource> downloadFileByOperationId(
} else if (fileContentType == PROPOSED_CHANGES_MARC_FILE) {
path = bulkOperation.getLinkToModifiedRecordsMarcFile();
} else if (fileContentType == COMMITTED_RECORDS_FILE) {
path = INSTANCE_MARC.equals(bulkOperation.getEntityType()) ?
bulkOperation.getLinkToCommittedRecordsMarcFile() :
bulkOperation.getLinkToCommittedRecordsCsvFile();
path = bulkOperation.getLinkToCommittedRecordsCsvFile();
} else if (fileContentType == COMMITTED_RECORDS_MARC_FILE) {
path = bulkOperation.getLinkToCommittedRecordsMarcFile();
} else if (fileContentType == COMMITTING_CHANGES_ERROR_FILE) {
path = bulkOperation.getLinkToCommittedRecordsErrorsCsvFile();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import static java.lang.Boolean.TRUE;
import static java.lang.Boolean.parseBoolean;
import static java.lang.String.format;
import static org.folio.bulkops.domain.dto.EntityType.INSTANCE_MARC;
import static org.folio.bulkops.domain.dto.UpdateOptionType.SUPPRESS_FROM_DISCOVERY;
import static org.folio.bulkops.util.Constants.APPLY_TO_HOLDINGS;
import static org.folio.bulkops.util.Constants.APPLY_TO_ITEMS;
import static org.folio.bulkops.util.Constants.GET_HOLDINGS_BY_INSTANCE_ID_QUERY;
import static org.folio.bulkops.util.Constants.GET_ITEMS_BY_HOLDING_ID_QUERY;
import static org.folio.bulkops.util.Constants.MARC;
import static org.folio.bulkops.util.Constants.MSG_NO_ADMINISTRATIVE_CHANGE_REQUIRED;
import static org.folio.bulkops.util.Constants.MSG_NO_CHANGE_REQUIRED;
import static org.folio.bulkops.util.FolioExecutionContextUtil.prepareContextForTenant;
import static org.folio.bulkops.util.RuleUtils.fetchParameters;
Expand Down Expand Up @@ -83,7 +85,7 @@ public void updateAssociatedRecords(ExtendedInstance extendedInstance, BulkOpera
.filter(rule -> applyRuleToAssociatedRecords(extendedInstance, rule, operation))
.isPresent();
if (notChanged) {
var errorMessage = buildErrorMessage(recordsUpdated, instance.getDiscoverySuppress());
var errorMessage = buildErrorMessage(recordsUpdated, instance.getDiscoverySuppress(), operation.getEntityType());
errorService.saveError(operation.getId(), instance.getIdentifier(operation.getIdentifierType()), errorMessage, ErrorType.WARNING);
}
}
Expand Down Expand Up @@ -168,11 +170,14 @@ private boolean suppressItemsIfRequired(List<HoldingsRecord> holdingsRecords, bo
return true;
}

private String buildErrorMessage(boolean recordsUpdated, boolean newValue) {
private String buildErrorMessage(boolean recordsUpdated, boolean newValue, EntityType entityType) {
var affectedState = TRUE.equals(newValue) ? "unsuppressed" : "suppressed";
var message = INSTANCE_MARC.equals(entityType) ?
MSG_NO_ADMINISTRATIVE_CHANGE_REQUIRED :
MSG_NO_CHANGE_REQUIRED;
return recordsUpdated ?
format(ERROR_MESSAGE_TEMPLATE, affectedState) :
MSG_NO_CHANGE_REQUIRED;
message;
}

private List<HoldingsRecord> getHoldingsSourceFolioByInstanceId(String instanceId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.folio.bulkops.repository;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

Expand All @@ -10,4 +11,5 @@
@Repository
public interface BulkOperationExecutionRepository extends JpaRepository<BulkOperationExecution, UUID> {
Optional<BulkOperationExecution> findByBulkOperationId(UUID uuid);
List<BulkOperationExecution> findAllByBulkOperationId(UUID uuid);
}
71 changes: 48 additions & 23 deletions src/main/java/org/folio/bulkops/service/BulkOperationService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.folio.bulkops.service;

import static java.lang.String.format;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.apache.commons.lang3.StringUtils.LF;
Expand Down Expand Up @@ -152,7 +153,7 @@ public class BulkOperationService {
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";
private static final String CHANGED_CSV_PATH_TEMPLATE = "%s/%s-Changed-Records-CSV-%s.csv";

private final ExecutorService executor = Executors.newCachedThreadPool();

Expand Down Expand Up @@ -379,16 +380,17 @@ public void commit(BulkOperation operation) {
var operationId = operation.getId();
operation.setCommittedNumOfRecords(0);
operation.setStatus(OperationStatusType.APPLY_CHANGES);
operation.setTotalNumOfRecords(operation.getMatchedNumOfRecords());

operation = bulkOperationRepository.save(operation);
var totalNumOfRecords = operation.getMatchedNumOfRecords();

if (operation.getEntityType() == INSTANCE_MARC) {
if (INSTANCE_MARC.equals(operation.getEntityType())) {
marcUpdateService.saveErrorsForFolioInstances(operation);
marcUpdateService.commitForInstanceMarc(operation);
return;
totalNumOfRecords *= getProgressMultiplier(operation);
}

operation.setTotalNumOfRecords(totalNumOfRecords);
operation = bulkOperationRepository.save(operation);

if (StringUtils.isNotEmpty(operation.getLinkToModifiedRecordsJsonFile())) {
var entityClass = resolveEntityClass(operation.getEntityType());
var extendedClass = resolveExtendedEntityClass(operation.getEntityType());
Expand Down Expand Up @@ -462,8 +464,6 @@ public void commit(BulkOperation operation) {
}

execution.setProcessedRecords(processedNumOfRecords);
operation.setProcessedNumOfRecords(operation.getCommittedNumOfRecords());
operation.setEndTime(LocalDateTime.now());
if (operation.getCommittedNumOfRecords() > 0) {
operation.setLinkToCommittedRecordsCsvFile(resultCsvFileName);
operation.setLinkToCommittedRecordsJsonFile(resultJsonFileName);
Expand All @@ -479,15 +479,21 @@ public void commit(BulkOperation operation) {
executionRepository.save(execution);
}

var linkToCommittingErrorsFile = errorService.uploadErrorsToStorage(operationId);
operation.setLinkToCommittedRecordsErrorsCsvFile(linkToCommittingErrorsFile);
operation.setCommittedNumOfErrors(errorService.getCommittedNumOfErrors(operationId));
operation.setCommittedNumOfWarnings(errorService.getCommittedNumOfWarnings(operationId));
marcUpdateService.commitForInstanceMarc(operation);

if (!FAILED.equals(operation.getStatus())) {
operation.setStatus(isEmpty(linkToCommittingErrorsFile) ? COMPLETED : COMPLETED_WITH_ERRORS);
if (!INSTANCE_MARC.equals(operation.getEntityType()) || isNull(operation.getLinkToModifiedRecordsMarcFile())) {
operation.setProcessedNumOfRecords(operation.getCommittedNumOfRecords());
operation.setEndTime(LocalDateTime.now());

var linkToCommittingErrorsFile = errorService.uploadErrorsToStorage(operationId);
operation.setLinkToCommittedRecordsErrorsCsvFile(linkToCommittingErrorsFile);
operation.setCommittedNumOfErrors(errorService.getCommittedNumOfErrors(operationId));

if (!FAILED.equals(operation.getStatus())) {
operation.setStatus(isEmpty(linkToCommittingErrorsFile) ? COMPLETED : COMPLETED_WITH_ERRORS);
}
bulkOperationRepository.save(operation);
}
bulkOperationRepository.save(operation);
}

private boolean isCurrentTenantNotCentral(String tenantId) {
Expand Down Expand Up @@ -658,17 +664,22 @@ public BulkOperation getOperationById(UUID bulkOperationId) {
yield operation;
}
case APPLY_CHANGES -> {
if (INSTANCE_MARC.equals(operation.getEntityType())) {
var executions = metadataProviderService.getJobExecutions(operation.getDataImportJobProfileId());
updateBulkOperationBasedOnDataImportState(executions, operation);
} else {
var execution = executionRepository.findByBulkOperationId(bulkOperationId);
if (execution.isPresent() && StatusType.ACTIVE.equals(execution.get().getStatus())) {
operation.setProcessedNumOfRecords(execution.get().getProcessedRecords());
var execution = executionRepository.findByBulkOperationId(bulkOperationId);
if (execution.isPresent() && StatusType.ACTIVE.equals(execution.get().getStatus())) {
var processedNumOfRecords = execution.get().getProcessedRecords();
if (INSTANCE_MARC.equals(operation.getEntityType())) {
var numOfErrors = operation.getCommittedNumOfErrors() * getProgressMultiplier(operation);
operation.setProcessedNumOfRecords(numOfErrors + processedNumOfRecords);
}
operation.setProcessedNumOfRecords(processedNumOfRecords);
}
yield bulkOperationRepository.save(operation);
}
case APPLY_MARC_CHANGES -> {
var executions = metadataProviderService.getJobExecutions(operation.getDataImportJobProfileId());
updateBulkOperationBasedOnDataImportState(executions, operation);
yield bulkOperationRepository.save(operation);
}
default -> operation;
};
}
Expand All @@ -692,8 +703,15 @@ public void processDataImportResult(UUID dataImportJobProfileId) {
}

private void updateBulkOperationBasedOnDataImportState(List<DataImportJobExecution> executions, BulkOperation operation) {
var numOfCommittedAdministrativeUpdates = executionRepository.findAllByBulkOperationId(operation.getId())
.stream()
.filter(execution -> StatusType.COMPLETED.equals(execution.getStatus()))
.map(BulkOperationExecution::getProcessedRecords)
.max(Integer::compareTo)
.orElse(0);
var processedNumOfRecords = metadataProviderService.calculateProgress(executions).getCurrent();
operation.setProcessedNumOfRecords(operation.getCommittedNumOfErrors() * 2 + processedNumOfRecords);
operation.setProcessedNumOfRecords(operation.getCommittedNumOfErrors() * getProgressMultiplier(operation) +
numOfCommittedAdministrativeUpdates + processedNumOfRecords);
}

public BulkOperation getBulkOperationOrThrow(UUID operationId) {
Expand Down Expand Up @@ -801,4 +819,11 @@ private synchronized void saveLinks(BulkOperation source) {
private boolean isCompletedSuccessfully(List<BulkOperationDataProcessing> list) {
return list.stream().allMatch(p -> StatusType.COMPLETED.equals(p.getStatus()));
}

private int getProgressMultiplier(BulkOperation operation) {
if (nonNull(operation.getLinkToModifiedRecordsMarcFile())) {
return nonNull(operation.getLinkToModifiedRecordsJsonFile()) ? 3 : 2;
}
return 1;
}
}
5 changes: 4 additions & 1 deletion src/main/java/org/folio/bulkops/service/ErrorService.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import static org.folio.bulkops.domain.dto.OperationStatusType.REVIEWED_NO_MARC_RECORDS;
import static org.folio.bulkops.domain.dto.OperationStatusType.REVIEW_CHANGES;
import static org.folio.bulkops.util.Constants.DATA_IMPORT_ERROR_DISCARDED;
import static org.folio.bulkops.util.Constants.MSG_NO_ADMINISTRATIVE_CHANGE_REQUIRED;
import static org.folio.bulkops.util.Constants.MSG_NO_MARC_CHANGE_REQUIRED;
import static org.folio.bulkops.util.Constants.MSG_NO_CHANGE_REQUIRED;

import java.io.ByteArrayInputStream;
Expand Down Expand Up @@ -63,7 +65,8 @@ public class ErrorService {
private final MetadataProviderClient metadataProviderClient;

public void saveError(UUID bulkOperationId, String identifier, String errorMessage, String uiErrorMessage, String link, ErrorType errorType) {
if (MSG_NO_CHANGE_REQUIRED.equals(errorMessage) && executionContentRepository.findFirstByBulkOperationIdAndIdentifier(bulkOperationId, identifier).isPresent()) {
if (Set.of(MSG_NO_CHANGE_REQUIRED, MSG_NO_ADMINISTRATIVE_CHANGE_REQUIRED, MSG_NO_MARC_CHANGE_REQUIRED).contains(errorMessage)
&& executionContentRepository.findFirstByBulkOperationIdAndIdentifier(bulkOperationId, identifier).isPresent()) {
return;
}
executionContentRepository.save(BulkOperationExecutionContent.builder()
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/org/folio/bulkops/service/MarcUpdateService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

import static java.util.Objects.nonNull;
import static org.folio.bulkops.domain.dto.IdentifierType.HRID;
import static org.folio.bulkops.domain.dto.OperationStatusType.APPLY_MARC_CHANGES;
import static org.folio.bulkops.domain.dto.OperationStatusType.FAILED;
import static org.folio.bulkops.util.Constants.MARC;
import static org.folio.bulkops.util.Constants.MSG_NO_CHANGE_REQUIRED;
import static org.folio.bulkops.util.Constants.MSG_NO_MARC_CHANGE_REQUIRED;
import static org.folio.bulkops.util.MarcHelper.fetchInstanceUuidOrElseHrid;

import com.fasterxml.jackson.core.JsonFactory;
Expand Down Expand Up @@ -36,7 +37,7 @@
@Log4j2
@RequiredArgsConstructor
public class MarcUpdateService {
public static final String CHANGED_MARC_PATH_TEMPLATE = "%s/%s-Changed-Records-%s.mrc";
public static final String CHANGED_MARC_PATH_TEMPLATE = "%s/%s-Changed-Records-MARC-%s.mrc";
public static final String MSG_BULK_EDIT_SUPPORTED_FOR_MARC_ONLY = "Bulk edit of MARC fields is supported only for instance with MARC source.";

private final BulkOperationExecutionRepository executionRepository;
Expand All @@ -49,8 +50,8 @@ public class MarcUpdateService {
@Transactional
public void commitForInstanceMarc(BulkOperation bulkOperation) {
if (StringUtils.isNotEmpty(bulkOperation.getLinkToModifiedRecordsMarcFile())) {
bulkOperation.setTotalNumOfRecords(bulkOperation.getTotalNumOfRecords() * 2);
bulkOperation.setProcessedNumOfRecords(bulkOperation.getProcessedNumOfRecords() * 2);
bulkOperation.setStatus(APPLY_MARC_CHANGES);
bulkOperationRepository.save(bulkOperation);

var execution = executionRepository.save(BulkOperationExecution.builder()
.bulkOperationId(bulkOperation.getId())
Expand Down Expand Up @@ -104,7 +105,7 @@ private String prepareCommittedFile(BulkOperation bulkOperation) throws IOExcept
var identifier = HRID.equals(bulkOperation.getIdentifierType()) ?
originalRecord.getControlNumber() :
fetchInstanceUuidOrElseHrid(originalRecord);
errorService.saveError(bulkOperation.getId(), identifier, MSG_NO_CHANGE_REQUIRED, ErrorType.WARNING);
errorService.saveError(bulkOperation.getId(), identifier, MSG_NO_MARC_CHANGE_REQUIRED, ErrorType.WARNING);
} else {
MarcDateHelper.updateDateTimeControlField(modifiedRecord, currentDate);
writerForResultMarcFile.writeRecord(modifiedRecord);
Expand Down
Loading
Loading