Skip to content

Commit

Permalink
MODORDERS-1102 - Order lines search results do not display fund code …
Browse files Browse the repository at this point in the history
…for orders created by data import (#943)

* Added logic to set poLine fundCode based on fundId populated during poLine mapping

* Deleted redundant call of order mapping process
  • Loading branch information
RuslanLavrov authored May 21, 2024
1 parent 2d58eb7 commit 88ac213
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 2 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
### Bug Fixes

* [MODORDERS-1090](https://folio-org.atlassian.net/browse/MODORDERS-1090) - Quantity = 0 for electronic format orders
* [MODORDERS-1102](https://folio-org.atlassian.net/browse/MODORDERS-1102) - Order lines search results do not display fund code for orders created by data import

## 12.8.0 - Released (Quesnelia R1 2024)
This release focused on fixing several bugs as well as implement new features and upgrading dependent libraries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
import static org.folio.ActionProfile.Action.CREATE;
import static org.folio.ActionProfile.FolioRecord.HOLDINGS;
import static org.folio.ActionProfile.FolioRecord.INSTANCE;
Expand Down Expand Up @@ -32,6 +33,7 @@
import java.time.Period;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
Expand All @@ -45,6 +47,7 @@
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -110,6 +113,9 @@ public class CreateOrderEventHandler implements EventHandler {
private static final String POL_ERESOURCE_FIELD = "eresource";
private static final String POL_PHYSICAL_FIELD = "physical";
private static final String POL_CREATE_INVENTORY_FIELD = "createInventory";
private static final String POL_FUND_DISTRIBUTION_FIELD = "fundDistribution";
private static final String POL_FUND_CODE_FIELD = "code";
private static final String POL_FUND_ID_FIELD = "fundId";
private static final String PO_LINE_KEY = "PO_LINE";
private static final String RECORD_ID_HEADER = "recordId";
private static final String JOB_PROFILE_SNAPSHOT_ID_KEY = "JOB_PROFILE_SNAPSHOT_ID";
Expand All @@ -119,6 +125,8 @@ public class CreateOrderEventHandler implements EventHandler {
private static final String WORKFLOW_STATUS_PATH = "order.po.workflowStatus";
private static final String PO_LINE_ORDER_ID_KEY = "purchaseOrderId";
private static final String DEFAULT_PO_LINES_LIMIT = "1";
private static final char LEFT_BRACKET = '(';
private static final char RIGHT_BRACKET = ')';

private final PurchaseOrderHelper purchaseOrderHelper;
private final PurchaseOrderLineHelper poLineHelper;
Expand Down Expand Up @@ -184,7 +192,6 @@ public CompletableFuture<DataImportEventPayload> handle(DataImportEventPayload d
future.completeExceptionally(result.cause());
} else {
Optional<Integer> poLinesLimitOptional = extractPoLinesLimit(dataImportEventPayload);
MappingManager.map(dataImportEventPayload, new MappingContext());

RequestContext requestContext = new RequestContext(Vertx.currentContext(), okapiHeaders);
Future<JsonObject> tenantConfigFuture = configurationEntriesCache.loadConfiguration(ORDER_CONFIG_MODULE_NAME, requestContext);
Expand Down Expand Up @@ -508,6 +515,7 @@ private Future<Void> prepareMappingResult(DataImportEventPayload dataImportEvent
JsonObject orderJson = mappingResult.getJsonObject(MAPPING_RESULT_FIELD).getJsonObject(ORDER_FIELD);
JsonObject poLineJson = mappingResult.getJsonObject(MAPPING_RESULT_FIELD).getJsonObject(PO_LINES_FIELD);
calculateActivationDue(poLineJson);
ensureFundCode(poLineJson, dataImportEventPayload);
dataImportEventPayload.getContext().put(ORDER.value(), orderJson.encode());

if (WorkflowStatus.OPEN.value().equals(orderJson.getString(ORDER_STATUS_FIELD))) {
Expand All @@ -533,6 +541,35 @@ private void calculateActivationDue(JsonObject poLineJson) {
}
}

private void ensureFundCode(JsonObject poLineJson, DataImportEventPayload dataImportEventPayload) {
if (!IterableUtils.isEmpty(poLineJson.getJsonArray(POL_FUND_DISTRIBUTION_FIELD))) {
Map<String, String> idToFundName = extractFundsData(dataImportEventPayload);

poLineJson.getJsonArray(POL_FUND_DISTRIBUTION_FIELD).stream()
.map(JsonObject.class::cast)
.filter(fundDistributionJson -> isNotEmpty(fundDistributionJson.getString(POL_FUND_ID_FIELD)))
.forEach(fundDistribution -> fundDistribution.put(POL_FUND_CODE_FIELD, determineFundCode(fundDistribution, idToFundName)));
}
}

private Map<String, String> extractFundsData(DataImportEventPayload dataImportEventPayload) {
ProfileSnapshotWrapper mappingProfileWrapper = dataImportEventPayload.getCurrentNode();
MappingProfile mappingProfile = ObjectMapperTool.getMapper().convertValue(mappingProfileWrapper.getContent(), MappingProfile.class);

return mappingProfile.getMappingDetails().getMappingFields().stream()
.filter(mappingRule -> POL_FUND_DISTRIBUTION_FIELD.equals(mappingRule.getName()) && !mappingRule.getSubfields().isEmpty())
.flatMap(mappingRule -> mappingRule.getSubfields().get(0).getFields().stream())
.filter(mappingRule -> POL_FUND_ID_FIELD.equals(mappingRule.getName()))
.map(mappingRule -> ((Map<String, String>) mappingRule.getAcceptedValues()))
.findAny()
.orElse(Collections.emptyMap());
}

private String determineFundCode(JsonObject fundDistribution, Map<String, String> idToFundName) {
String fundName = idToFundName.get(fundDistribution.getString(POL_FUND_ID_FIELD));
return fundName.substring(fundName.lastIndexOf(LEFT_BRACKET) + 1, fundName.lastIndexOf(RIGHT_BRACKET));
}

private Future<Void> overrideCreateInventoryField(JsonObject poLineJson, DataImportEventPayload dataImportEventPayload) {
String profileSnapshotId = dataImportEventPayload.getContext().get(JOB_PROFILE_SNAPSHOT_ID_KEY);
Map<String, String> headers = DataImportUtils.extractOkapiHeaders(dataImportEventPayload);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.folio.rest.jaxrs.model.MappingRule;
import org.folio.rest.jaxrs.model.Physical;
import org.folio.rest.jaxrs.model.ProfileSnapshotWrapper;
import org.folio.rest.jaxrs.model.RepeatableSubfieldMapping;
import org.folio.service.dataimport.PoLineImportProgressService;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
Expand Down Expand Up @@ -91,6 +92,8 @@
import static org.folio.rest.jaxrs.model.CompositePoLine.OrderFormat.P_E_MIX;
import static org.folio.rest.jaxrs.model.EntityType.MARC_BIBLIOGRAPHIC;
import static org.folio.rest.jaxrs.model.EntityType.ORDER;
import static org.folio.rest.jaxrs.model.FundDistribution.DistributionType.PERCENTAGE;
import static org.folio.rest.jaxrs.model.MappingRule.RepeatableFieldAction.EXTEND_EXISTING;
import static org.folio.rest.jaxrs.model.ProfileSnapshotWrapper.ContentType.ACTION_PROFILE;
import static org.folio.rest.jaxrs.model.ProfileSnapshotWrapper.ContentType.JOB_PROFILE;
import static org.folio.rest.jaxrs.model.ProfileSnapshotWrapper.ContentType.MAPPING_PROFILE;
Expand Down Expand Up @@ -578,7 +581,7 @@ public void shouldCreatePendingOrderAndPublishDiCompletedEventWhenOpenStatusSpec
assertEquals(DI_ORDER_CREATED.value(), eventPayload.getEventsChain().get(eventPayload.getEventsChain().size() - 1));

CompositePurchaseOrder order = Json.decodeValue(eventPayload.getContext().get(ActionProfile.FolioRecord.ORDER.value()), CompositePurchaseOrder.class);
assertEquals(order.getApproved(), Boolean.FALSE);
assertEquals(Boolean.FALSE, order.getApproved());

verifyOrder(eventPayload);
verifyPoLine(eventPayload);
Expand Down Expand Up @@ -1501,6 +1504,61 @@ public void shouldCreatePendingOrderAndNotMapVendorMaterialSupplierAndAccessProv
assertNull(poLine.getEresource());
}

@Test
public void shouldCreatePoLineWithFundIdAndFundCode() throws InterruptedException {
// given
String expectedFundId = "7fbd5d84-62d1-44c6-9c45-6cb173998bbd";
String expectedFundCode = "AFRICAHIST";
double expectedDistributionValue = 100;

MappingRule fundDistributionsRule = new MappingRule()
.withName("fundDistribution")
.withPath("order.poLine.fundDistribution[]")
.withEnabled("true")
.withRepeatableFieldAction(EXTEND_EXISTING)
.withSubfields(List.of(new RepeatableSubfieldMapping()
.withOrder(0)
.withPath("order.poLine.fundDistribution[]")
.withFields(List.of(
new MappingRule().withPath("order.poLine.fundDistribution[].fundId").withName("fundId")
.withValue("\"African (History) (AFRICAHIST)\"")
.withAcceptedValues(new HashMap<>(Map.of(expectedFundId, "African (History) (AFRICAHIST)"))),
new MappingRule().withPath("order.poLine.fundDistribution[].value").withValue("\"100\""),
new MappingRule().withPath("order.poLine.fundDistribution[].distributionType").withValue("\"percentage\"")))
));

mappingProfile.getMappingDetails().getMappingFields().add(fundDistributionsRule);
ProfileSnapshotWrapper profileSnapshotWrapper = buildProfileSnapshotWrapper(jobProfile, actionProfile, mappingProfile);
addMockEntry(JOB_PROFILE_SNAPSHOTS_MOCK, profileSnapshotWrapper);

DataImportEventPayload dataImportEventPayload = new DataImportEventPayload()
.withJobExecutionId(jobExecutionJson.getString(ID_FIELD))
.withEventType(DI_INCOMING_MARC_BIB_FOR_ORDER_PARSED.value())
.withTenant(TENANT_ID)
.withOkapiUrl(OKAPI_URL)
.withToken(TOKEN)
.withContext(new HashMap<>() {{
put(MARC_BIBLIOGRAPHIC.value(), Json.encode(record));
put(JOB_PROFILE_SNAPSHOT_ID_KEY, profileSnapshotWrapper.getId());
}});

SendKeyValues<String, String> request = prepareKafkaRequest(dataImportEventPayload);

// when
kafkaCluster.send(request);

// then
DataImportEventPayload eventPayload = observeEvent(DI_COMPLETED.value());
verifyOrder(eventPayload);
CompositePoLine createdPoLine = verifyPoLine(eventPayload);
assertNotNull(createdPoLine.getFundDistribution());
assertEquals(1, createdPoLine.getFundDistribution().size());
assertEquals(expectedFundId, createdPoLine.getFundDistribution().get(0).getFundId());
assertEquals(expectedFundCode, createdPoLine.getFundDistribution().get(0).getCode());
assertEquals(expectedDistributionValue, createdPoLine.getFundDistribution().get(0).getValue());
assertEquals(PERCENTAGE, createdPoLine.getFundDistribution().get(0).getDistributionType());
}

@Test
public void shouldReturnFailedByDuplicateEventExceptionFutureWhenRecordIdIsDuplicated(TestContext context) {
Async async = context.async();
Expand Down

0 comments on commit 88ac213

Please sign in to comment.