Skip to content
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
4 changes: 2 additions & 2 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@
"inventory-storage.nature-of-content-terms.item.get",
"inventory-storage.instance-formats.collection.get",
"inventory-storage.instance-formats.item.get",
"inventory.instances.item.put",
"inventory.instances.item.patch",
"inventory-storage.instance-note-types.item.get",
"inventory-storage.instance-note-types.collection.get",
"consortia.consortium.item.get",
Expand Down Expand Up @@ -556,7 +556,7 @@
},
{
"id": "inventory",
"version": "12.0 13.0 14.0"
"version": "14.4"
},
{
"id": "locations",
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/org/folio/bulkops/client/InstanceClient.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
package org.folio.bulkops.client;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import org.folio.bulkops.configs.FeignClientConfiguration;
import org.folio.bulkops.domain.bean.BriefInstanceCollection;
import org.folio.bulkops.domain.bean.Instance;
import org.folio.bulkops.domain.bean.InstanceCollection;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "inventory/instances", configuration = FeignClientConfiguration.class)
public interface InstanceClient {
@PutMapping(value = "/{instanceId}")
void updateInstance(@RequestBody Instance instance, @PathVariable String instanceId);
@PatchMapping(value = "/{instanceId}")
void patchInstance(@RequestBody ObjectNode patch, @PathVariable String instanceId);

@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
BriefInstanceCollection getByQuery(@RequestParam String query);
Expand Down
24 changes: 16 additions & 8 deletions src/main/java/org/folio/bulkops/domain/bean/Instance.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@
@JsonTypeName("instance")
@EqualsAndHashCode(exclude = "version")
public class Instance implements BulkOperationsEntity {
public static final String INSTANCE_JSON_ID = "id";
public static final String INSTANCE_JSON_VERSION = "_version";
public static final String INSTANCE_JSON_DISCOVERY_SUPPRESS = "discoverySuppress";
public static final String INSTANCE_JSON_STAFF_SUPPRESS = "staffSuppress";
public static final String INSTANCE_JSON_DELETED = "deleted";
public static final String INSTANCE_JSON_ADM_NOTES = "administrativeNotes";
public static final String INSTANCE_JSON_NOTES = "notes";
public static final String INSTANCE_JSON_STATISTICAL_CODES = "statisticalCodeIds";
public static final String INSTANCE_UUID = "Instance UUID";
public static final String INSTANCE_HRID = "Instance HRID";
public static final String INSTANCE_SOURCE = "Source";
Expand Down Expand Up @@ -70,24 +78,24 @@ public class Instance implements BulkOperationsEntity {
public static final String INSTANCE_PUBLICATION = "Publication";
public static final String INSTANCE_SET_FOR_DELETION = "Set for deletion";

@JsonProperty("id")
@JsonProperty(INSTANCE_JSON_ID)
@CsvCustomBindByName(column = INSTANCE_UUID, converter = StringConverter.class)
@CsvCustomBindByPosition(position = 0, converter = StringConverter.class)
@UnifiedTableCell(visible = false)
private String id;

@JsonProperty("_version")
@JsonProperty(INSTANCE_JSON_VERSION)
private Integer version;

@JsonProperty("discoverySuppress")
@JsonProperty(INSTANCE_JSON_DISCOVERY_SUPPRESS)
@CsvCustomBindByName(
column = INSTANCE_SUPPRESS_FROM_DISCOVERY,
converter = BooleanConverter.class)
@CsvCustomBindByPosition(position = 1, converter = BooleanConverter.class)
@UnifiedTableCell
private Boolean discoverySuppress;

@JsonProperty("staffSuppress")
@JsonProperty(INSTANCE_JSON_STAFF_SUPPRESS)
@CsvCustomBindByName(column = INSTANCE_STAFF_SUPPRESS, converter = BooleanConverter.class)
@CsvCustomBindByPosition(position = 2, converter = BooleanConverter.class)
@UnifiedTableCell(visible = false)
Expand All @@ -99,7 +107,7 @@ public class Instance implements BulkOperationsEntity {
@UnifiedTableCell(visible = false)
private Boolean previouslyHeld;

@JsonProperty("deleted")
@JsonProperty(INSTANCE_JSON_DELETED)
@Valid
@CsvCustomBindByName(column = INSTANCE_SET_FOR_DELETION, converter = BooleanConverter.class)
@CsvCustomBindByPosition(position = 4, converter = BooleanConverter.class)
Expand Down Expand Up @@ -138,15 +146,15 @@ public class Instance implements BulkOperationsEntity {
@UnifiedTableCell(visible = false)
private String modeOfIssuanceId;

@JsonProperty("statisticalCodeIds")
@JsonProperty(INSTANCE_JSON_STATISTICAL_CODES)
@CsvCustomBindByName(
column = INSTANCE_STATISTICAL_CODES,
converter = InstanceStatisticalCodeListConverter.class)
@CsvCustomBindByPosition(position = 10, converter = InstanceStatisticalCodeListConverter.class)
@UnifiedTableCell(visible = false)
private List<String> statisticalCodeIds;

@JsonProperty("administrativeNotes")
@JsonProperty(INSTANCE_JSON_ADM_NOTES)
@CsvCustomBindByName(
column = INSTANCE_ADMINISTRATIVE_NOTE,
converter = StringListPipedConverter.class)
Expand Down Expand Up @@ -242,7 +250,7 @@ public class Instance implements BulkOperationsEntity {
@UnifiedTableCell(visible = false)
private List<String> publicationRange;

@JsonProperty("notes")
@JsonProperty(INSTANCE_JSON_NOTES)
@CsvCustomBindByName(column = INSTANCE_NOTES, converter = InstanceNoteListConverter.class)
@CsvCustomBindByPosition(position = 25, converter = InstanceNoteListConverter.class)
@UnifiedTableCell(visible = false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package org.folio.bulkops.processor;

import org.folio.bulkops.domain.dto.BulkOperationRuleCollection;
import org.folio.bulkops.domain.entity.BulkOperation;

public interface FolioUpdateProcessor<T> {
void updateRecord(T t);
void updateRecord(T t, BulkOperationRuleCollection rules);

void updateAssociatedRecords(T t, BulkOperation bulkOperation, boolean notChanged);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.folio.bulkops.domain.bean.Item;
import org.folio.bulkops.domain.bean.ItemCollection;
import org.folio.bulkops.domain.dto.BulkOperationRule;
import org.folio.bulkops.domain.dto.BulkOperationRuleCollection;
import org.folio.bulkops.domain.dto.EntityType;
import org.folio.bulkops.domain.dto.ErrorType;
import org.folio.bulkops.domain.entity.BulkOperation;
Expand Down Expand Up @@ -74,13 +75,13 @@ public class FolioInstanceUpdateProcessor extends FolioAbstractUpdateProcessor<E
private final PermissionsValidator permissionsValidator;

@Override
public void updateRecord(ExtendedInstance extendedInstance) {
public void updateRecord(ExtendedInstance extendedInstance, BulkOperationRuleCollection rules) {
permissionsValidator.checkIfBulkEditWritePermissionExists(
extendedInstance.getTenantId(),
EntityType.INSTANCE,
NO_INSTANCE_WRITE_PERMISSIONS_TEMPLATE + extendedInstance.getTenantId());
var instance = extendedInstance.getEntity();
instanceClient.updateInstance(instance.withIsbn(null).withIssn(null), instance.getId());
var patchData = InstancePatchUtils.fetchChangedData(extendedInstance.getEntity(), rules);
instanceClient.patchInstance(patchData, extendedInstance.getEntity().getId());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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.EntityType;
import org.folio.bulkops.domain.dto.ErrorType;
import org.folio.bulkops.domain.entity.BulkOperation;
Expand Down Expand Up @@ -54,7 +55,8 @@ public class HoldingsUpdateProcessor extends FolioAbstractUpdateProcessor<Extend
private final PermissionsValidator permissionsValidator;

@Override
public void updateRecord(ExtendedHoldingsRecord extendedHoldingsRecord) {
public void updateRecord(
ExtendedHoldingsRecord extendedHoldingsRecord, BulkOperationRuleCollection rules) {
var holdingsRecord = extendedHoldingsRecord.getEntity();
if (consortiaService.isTenantCentral(folioExecutionContext.getTenantId())) {
var tenantId = extendedHoldingsRecord.getTenantId();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package org.folio.bulkops.processor.folio;

import static java.util.Objects.isNull;
import static org.folio.bulkops.domain.bean.Instance.INSTANCE_JSON_ADM_NOTES;
import static org.folio.bulkops.domain.bean.Instance.INSTANCE_JSON_DELETED;
import static org.folio.bulkops.domain.bean.Instance.INSTANCE_JSON_DISCOVERY_SUPPRESS;
import static org.folio.bulkops.domain.bean.Instance.INSTANCE_JSON_ID;
import static org.folio.bulkops.domain.bean.Instance.INSTANCE_JSON_NOTES;
import static org.folio.bulkops.domain.bean.Instance.INSTANCE_JSON_STAFF_SUPPRESS;
import static org.folio.bulkops.domain.bean.Instance.INSTANCE_JSON_STATISTICAL_CODES;
import static org.folio.bulkops.domain.bean.Instance.INSTANCE_JSON_VERSION;
import static org.folio.bulkops.domain.dto.UpdateActionType.CHANGE_TYPE;
import static org.folio.bulkops.domain.dto.UpdateOptionType.ADMINISTRATIVE_NOTE;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.BooleanNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.Objects;
import lombok.experimental.UtilityClass;
import org.folio.bulkops.domain.bean.Instance;
import org.folio.bulkops.domain.dto.BulkOperationRule;
import org.folio.bulkops.domain.dto.BulkOperationRuleCollection;

@UtilityClass
public class InstancePatchUtils {
private static final ObjectMapper mapper = new ObjectMapper();

public static ObjectNode fetchChangedData(Instance instance, BulkOperationRuleCollection rules) {
var result = mapper.createObjectNode();

result.put(INSTANCE_JSON_ID, instance.getId());
result.set(
INSTANCE_JSON_VERSION,
isNull(instance.getVersion()) ? mapper.nullNode() : IntNode.valueOf(instance.getVersion()));

var details =
rules.getBulkOperationRules().stream()
.map(BulkOperationRule::getRuleDetails)
.filter(Objects::nonNull)
.toList();

for (var ruleDetails : details) {
if (ruleDetails.getOption() != null) {
switch (ruleDetails.getOption()) {
case STAFF_SUPPRESS -> addStaffSuppress(result, instance);
case SUPPRESS_FROM_DISCOVERY -> addDiscoverySuppress(result, instance);
case SET_RECORDS_FOR_DELETE -> addSetForDeletion(result, instance);
case STATISTICAL_CODE -> addStatisticalCode(result, instance);
case ADMINISTRATIVE_NOTE -> {
addAdministrativeNotes(result, instance);
if (CHANGE_TYPE.equals(ruleDetails.getActions().getFirst().getType())) {
addInstanceNotes(result, instance);
}
}
case INSTANCE_NOTE -> {
addInstanceNotes(result, instance);
if (CHANGE_TYPE.equals(ruleDetails.getActions().getFirst().getType())
&& ADMINISTRATIVE_NOTE
.getValue()
.equals(ruleDetails.getActions().getFirst().getUpdated())) {
addAdministrativeNotes(result, instance);
}
}
default ->
throw new IllegalArgumentException(
"Rule option %s is not supported".formatted(ruleDetails.getOption()));
}
}
}
return result;
}

private static void addStaffSuppress(ObjectNode node, Instance instance) {
node.set(
INSTANCE_JSON_STAFF_SUPPRESS,
isNull(instance.getStaffSuppress())
? mapper.nullNode()
: BooleanNode.valueOf(instance.getStaffSuppress()));
}

private static void addDiscoverySuppress(ObjectNode node, Instance instance) {
node.set(
INSTANCE_JSON_DISCOVERY_SUPPRESS,
isNull(instance.getDiscoverySuppress())
? mapper.nullNode()
: BooleanNode.valueOf(instance.getDiscoverySuppress()));
}

private static void addSetForDeletion(ObjectNode node, Instance instance) {
node.set(
INSTANCE_JSON_DELETED,
isNull(instance.getDeleted())
? mapper.nullNode()
: BooleanNode.valueOf(instance.getDeleted()));
addStaffSuppress(node, instance);
addDiscoverySuppress(node, instance);
}

private static void addStatisticalCode(ObjectNode node, Instance instance) {
node.set(INSTANCE_JSON_STATISTICAL_CODES, mapper.valueToTree(instance.getStatisticalCodeIds()));
}

private static void addAdministrativeNotes(ObjectNode node, Instance instance) {
node.set(INSTANCE_JSON_ADM_NOTES, mapper.valueToTree(instance.getAdministrativeNotes()));
}

private static void addInstanceNotes(ObjectNode node, Instance instance) {
node.set(INSTANCE_JSON_NOTES, mapper.valueToTree(instance.getInstanceNotes()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.RequiredArgsConstructor;
import org.folio.bulkops.client.ItemClient;
import org.folio.bulkops.domain.bean.ExtendedItem;
import org.folio.bulkops.domain.dto.BulkOperationRuleCollection;
import org.folio.bulkops.domain.dto.EntityType;
import org.folio.bulkops.processor.FolioAbstractUpdateProcessor;
import org.folio.bulkops.processor.permissions.check.PermissionsValidator;
Expand All @@ -29,7 +30,7 @@ public class ItemUpdateProcessor extends FolioAbstractUpdateProcessor<ExtendedIt
private final PermissionsValidator permissionsValidator;

@Override
public void updateRecord(ExtendedItem extendedItem) {
public void updateRecord(ExtendedItem extendedItem, BulkOperationRuleCollection rules) {
var item = extendedItem.getEntity();
if (consortiaService.isTenantCentral(folioExecutionContext.getTenantId())) {
var tenantId = extendedItem.getTenantId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lombok.RequiredArgsConstructor;
import org.folio.bulkops.client.UserClient;
import org.folio.bulkops.domain.bean.User;
import org.folio.bulkops.domain.dto.BulkOperationRuleCollection;
import org.folio.bulkops.domain.dto.EntityType;
import org.folio.bulkops.processor.FolioAbstractUpdateProcessor;
import org.folio.bulkops.processor.permissions.check.PermissionsValidator;
Expand All @@ -22,7 +23,7 @@ public class UserUpdateProcessor extends FolioAbstractUpdateProcessor<User> {
private final FolioExecutionContext folioExecutionContext;

@Override
public void updateRecord(User user) {
public void updateRecord(User user, BulkOperationRuleCollection rules) {
permissionsValidator.checkIfBulkEditWritePermissionExists(
folioExecutionContext.getTenantId(),
EntityType.USER,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class RecordUpdateService {
private final FolioUpdateProcessorFactory updateProcessorFactory;
private final BulkOperationExecutionContentRepository executionContentRepository;
private final EntityPathResolver entityPathResolver;
private final RuleService ruleService;

public BulkOperationsEntity updateEntity(
BulkOperationsEntity original, BulkOperationsEntity modified, BulkOperation operation) {
Expand All @@ -36,7 +37,7 @@ public BulkOperationsEntity updateEntity(
resolveExtendedEntityClass(operation.getEntityType()));
if (!isEqual) {
try {
updater.updateRecord(modified);
updater.updateRecord(modified, ruleService.getRules(operation.getId()));
} catch (FeignException e) {
if (e.status() == 409 && e.getMessage().contains("optimistic locking")) {
var message = Utils.getMessageFromFeignException(e);
Expand Down
Loading
Loading