Skip to content

Commit

Permalink
Merge branch 'master' into MODEXPW-489
Browse files Browse the repository at this point in the history
  • Loading branch information
siarhei-charniak authored Aug 12, 2024
2 parents 5d4684f + 3a92660 commit d67353b
Show file tree
Hide file tree
Showing 15 changed files with 222 additions and 74 deletions.
2 changes: 1 addition & 1 deletion folio-export-common
7 changes: 7 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,13 @@
<version>${marc4j.version}</version>
</dependency>

<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.4.2</version>
<type>pom</type>
</dependency>

<!-- Test dependencies -->

<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.folio.dew.domain.dto.CompositePoLine;
import org.folio.dew.domain.dto.CompositePurchaseOrder;
import org.folio.dew.domain.dto.acquisitions.edifact.EdiFileConfig;
import org.folio.dew.error.NotFoundException;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
Expand Down Expand Up @@ -37,21 +38,26 @@ public void convertPOtoEdifact(EDIStreamWriter writer, CompositePurchaseOrder co
messageSegmentCount++;
writeOrderDate(compPO, writer);

String shipToAddress = configurationService.getAddressConfig(compPO.getShipTo());
messageSegmentCount++;
writeLibrary(ediFileConfig, writer);
writeLibrary(ediFileConfig, shipToAddress, writer);

messageSegmentCount++;
writeVendor(ediFileConfig, writer);

if (!compPO.getCompositePoLines().isEmpty()
&& compPO.getCompositePoLines().get(0).getVendorDetail() != null
&& StringUtils.isNotBlank(compPO.getCompositePoLines().get(0).getVendorDetail().getVendorAccount())){
if (compPO.getCompositePoLines().isEmpty()) {
String errMsg = String.format("CompositePoLines is not found for CompositeOrder '%s'", compPO.getId());
throw new NotFoundException(errMsg);
}

var comPoLine = compPO.getCompositePoLines().get(0);
if (comPoLine.getVendorDetail() != null && StringUtils.isNotBlank(comPoLine.getVendorDetail().getVendorAccount())){
messageSegmentCount++;
writeAccountNumber(compPO.getCompositePoLines().get(0).getVendorDetail().getVendorAccount(), writer);
writeAccountNumber(comPoLine.getVendorDetail().getVendorAccount(), writer);
}

messageSegmentCount++;
String currency = configurationService.getSystemCurrency();
String currency = comPoLine.getCost().getCurrency();
writeCurrency(currency, writer);

// Order lines
Expand Down Expand Up @@ -113,14 +119,20 @@ private void writeOrderDate(CompositePurchaseOrder compPO, EDIStreamWriter write
}

// Library ID and ID type
private void writeLibrary(EdiFileConfig ediFileConfig, EDIStreamWriter writer) throws EDIStreamException {
private void writeLibrary(EdiFileConfig ediFileConfig, String shipToAddress, EDIStreamWriter writer) throws EDIStreamException {
writer.writeStartSegment("NAD")
.writeElement("BY")
.writeStartElement()
.writeComponent(ediFileConfig.getLibEdiCode())
.writeComponent("")
.writeComponent(ediFileConfig.getLibEdiType())
.endElement()
.writeStartElement()
.writeComponent("")
.endElement()
.writeStartElement()
.writeComponent(shipToAddress)
.endElement()
.writeEndSegment();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package org.folio.dew.batch.acquisitions.edifact;

import javax.money.CurrencyUnit;
import javax.money.Monetary;
import javax.money.MonetaryAmount;

import io.xlate.edi.stream.EDIStreamException;
import io.xlate.edi.stream.EDIStreamWriter;
import liquibase.util.StringUtil;
Expand All @@ -10,10 +14,12 @@
import org.folio.dew.batch.acquisitions.edifact.services.MaterialTypeService;
import org.folio.dew.domain.dto.CompositePoLine;
import org.folio.dew.domain.dto.Contributor;
import org.folio.dew.domain.dto.Cost;
import org.folio.dew.domain.dto.FundDistribution;
import org.folio.dew.domain.dto.Location;
import org.folio.dew.domain.dto.ProductIdentifier;
import org.folio.dew.domain.dto.ReferenceNumberItem;
import org.javamoney.moneta.Money;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
Expand Down Expand Up @@ -106,6 +112,12 @@ public int convertPOLine(CompositePoLine poLine, EDIStreamWriter writer, int cur
writePrice(poLine.getCost().getPoLineEstimatedPrice(), writer);
}

if (poLine.getCost().getListUnitPrice() != null || poLine.getCost().getListUnitPriceElectronic() != null) {
messageSegmentCount++;
String totalUnitPrice = calculateCostUnitsTotal(poLine.getCost());
writeUnitPrice(totalUnitPrice, writer);
}

messageSegmentCount++;
writePoLineCurrency(poLine, writer);

Expand Down Expand Up @@ -291,6 +303,15 @@ private void writePrice(BigDecimal price, EDIStreamWriter writer) throws EDIStre
.writeEndSegment();
}

private void writeUnitPrice(String price, EDIStreamWriter writer) throws EDIStreamException {
writer.writeStartSegment("PRI")
.writeStartElement()
.writeComponent("AAB")
.writeComponent(price)
.endElement()
.writeEndSegment();
}

private void writePoLineCurrency(CompositePoLine poLine, EDIStreamWriter writer) throws EDIStreamException {
writer.writeStartSegment("CUX")
.writeStartElement()
Expand Down Expand Up @@ -452,4 +473,33 @@ private String getLocationCode(Location location) {
}
return "";
}


/**
* The method is using calculation that similar to calculation in mod-order (HelperUtils -> calculateCostUnitsTotal),
* but without additional cost and discount.
*
* @param cost Cost object of ComPoLine
* @return unit price without discount and additional cost
*/
private String calculateCostUnitsTotal(Cost cost) {
CurrencyUnit currency = Monetary.getCurrency(cost.getCurrency());
MonetaryAmount total = Money.of(0, currency);

// Physical resources price
if (cost.getListUnitPrice() != null && cost.getQuantityPhysical() != null) {
MonetaryAmount pPrice = Money.of(cost.getListUnitPrice(), currency)
.multiply(cost.getQuantityPhysical());
total = total.add(pPrice);
}

// Electronic resources price
if (cost.getListUnitPriceElectronic() != null && cost.getQuantityElectronic() != null) {
MonetaryAmount ePrice = Money.of(cost.getListUnitPriceElectronic(), currency)
.multiply(cost.getQuantityElectronic());
total = total.add(ePrice);
}

return total.toString();
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
package org.folio.dew.batch.acquisitions.edifact.services;

import java.util.UUID;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.folio.dew.client.ConfigurationClient;
import org.folio.dew.domain.dto.ConfigurationCollection;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.dew.client.ConfigurationClient;
import org.folio.dew.domain.dto.ModelConfiguration;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ConfigurationService {

private static final Logger logger = LogManager.getLogger();

private final ConfigurationClient configurationClient;
private final ObjectMapper objectMapper;

private ConfigurationCollection getLocaleSettings() {
return configurationClient.getConfigurations("(module==ORG and configName==localeSettings)");
private ModelConfiguration getConfigById(String configId) {
return configurationClient.getConfigById(configId);
}

public String getSystemCurrency() {
ConfigurationCollection configs = getLocaleSettings();

if (configs == null || configs.getTotalRecords() == 0) {
return "USD";
@Cacheable(cacheNames = "addressConfiguration")
public String getAddressConfig(UUID shipToConfigId) {
if (shipToConfigId == null) {
logger.warn("getAddressConfig:: 'shipTo' field of composite purchase order is null");
return "";
}

var jsonObject = objectMapper.valueToTree(configs.getConfigs().get(0).getValue());

if (!jsonObject.has("currency")) {
return "USD";
var addressConfig = getConfigById(shipToConfigId.toString());
if (addressConfig.getValue() == null) {
logger.warn("getAddressConfig:: 'address config with id '{}' is not found", shipToConfigId);
return "";
}
try {
JsonNode valueJsonObject = objectMapper.readTree(addressConfig.getValue());
return valueJsonObject.has("address") ? valueJsonObject.get("address").asText() : "";
} catch (JsonProcessingException e) {
logger.error("getAddressConfig:: Couldn't convert configValue: {} to json", addressConfig, e);
return "";
}

return String.valueOf(jsonObject.get("currency"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ public ExtendedItemCollection process(ItemIdentifier itemIdentifier) throws Bulk
tenantIds.forEach(tenantId -> {
try (var context = new FolioExecutionContextSetter(refreshAndGetFolioExecutionContext(tenantId, folioExecutionContext))) {
var url = format(getMatchPattern(identifierType), idType, identifier);
var itemCollection = inventoryClient.getItemByQuery(url, limit);
if (itemCollection.getTotalRecords() > limit) {
var itemCollection = inventoryClient.getItemByQuery(url, Integer.MAX_VALUE);
if (itemCollection.getItems().size() > limit) {
log.error("Central tenant case: response from {} for tenant {}: {}", url, tenantId, getResponseAsString(itemCollection));
throw new BulkEditException(MULTIPLE_MATCHES_MESSAGE);
}
Expand All @@ -118,8 +118,8 @@ public ExtendedItemCollection process(ItemIdentifier itemIdentifier) throws Bulk
// Process local tenant case
var url = format(getMatchPattern(identifierType), idType, identifier);
var currentTenantId = folioExecutionContext.getTenantId();
var itemCollection = inventoryClient.getItemByQuery(url, limit);
if (itemCollection.getTotalRecords() > limit) {
var itemCollection = inventoryClient.getItemByQuery(url, Integer.MAX_VALUE);
if (itemCollection.getItems().size() > limit) {
log.error("Member/local tenant case: response from {} for tenant {}: {}", url, currentTenantId, getResponseAsString(itemCollection));
throw new BulkEditException(MULTIPLE_MATCHES_MESSAGE);
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/folio/dew/client/ConfigurationClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
Expand All @@ -16,6 +17,9 @@ public interface ConfigurationClient {
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
ConfigurationCollection getConfigurations(@RequestParam("query") String query);

@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE, path = "/{entryId}")
ModelConfiguration getConfigById(@PathVariable String entryId);

@PostMapping
ModelConfiguration postConfiguration(@RequestBody ModelConfiguration config);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,35 @@

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.UUID;
import java.util.stream.Stream;

import org.folio.dew.BaseBatchTest;
import org.folio.dew.batch.acquisitions.edifact.services.ConfigurationService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;


class ConfigurationServiceTest extends BaseBatchTest {

@Autowired
private ConfigurationService configurationService;

@Test
void getCurrency() {
String currency = configurationService.getSystemCurrency();
assertEquals("USD", currency);
static Stream<Arguments> provideAddressConfigData() {
return Stream.of(
Arguments.of("1947e709-8d60-42e2-8dde-7566ae446d24", "Address 123"), // existing config
Arguments.of(null, ""), // null config ID
Arguments.of("116a38c2-cac3-4f08-816b-afebfebe453d", ""), // non-existing config
Arguments.of("8ea92aa2-7b11-4f0e-9ed2-ab8fe281f37f", "") // config without address value
);
}

@ParameterizedTest
@MethodSource("provideAddressConfigData")
void testGetAddressConfig(String addressConfigId, String expectedAddress) {
UUID configId = addressConfigId != null ? UUID.fromString(addressConfigId) : null;
String address = configurationService.getAddressConfig(configId);
assertEquals(expectedAddress, address);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.AdditionalMatchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;

Expand Down Expand Up @@ -137,8 +138,8 @@ private void serviceMocks() {
.thenReturn("KU/CC/DI/M");
Mockito.when(holdingService.getPermanentLocationByHoldingId(anyString()))
.thenReturn("fcd64ce1-6995-48f0-840e-89ffa2288371");
Mockito.when(configurationService.getSystemCurrency())
.thenReturn("GBP");
Mockito.when(configurationService.getAddressConfig(any()))
.thenReturn("Bockenheimer Landstr. 134-13");
}

private void validateEdifactOrders(String ediOrder, String fileId) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

import java.nio.file.Path;
import java.util.Collections;
import java.util.List;

class BulkEditProcessorsTest extends BaseBatchTest {
@Autowired
Expand Down Expand Up @@ -127,8 +128,8 @@ void shouldNotIncludeDuplicatedUsers(String identifierType) {
@ValueSource(strings = {"ID", "HRID", "BARCODE", "FORMER_IDS", "ACCESSION_NUMBER"})
@SneakyThrows
void shouldNotIncludeDuplicatedItems(String identifierType) {
when(inventoryClient.getItemByQuery(String.format(getMatchPattern(identifierType), resolveIdentifier(identifierType), "duplicateIdentifier"), 1)).thenReturn(new ItemCollection().items(Collections.singletonList(new Item())).totalRecords(2));
when(inventoryClient.getItemByQuery("barcode==\"duplicateIdentifier\"", 1)).thenReturn(new ItemCollection().items(Collections.singletonList(new Item())).totalRecords(2));
when(inventoryClient.getItemByQuery(String.format(getMatchPattern(identifierType), resolveIdentifier(identifierType), "duplicateIdentifier"), Integer.MAX_VALUE)).thenReturn(new ItemCollection().items(List.of(new Item(), new Item())).totalRecords(2));
when(inventoryClient.getItemByQuery("barcode==\"duplicateIdentifier\"", Integer.MAX_VALUE)).thenReturn(new ItemCollection().items(List.of(new Item(), new Item())).totalRecords(2));
StepExecution stepExecution = MetaDataInstanceFactory.createStepExecution(new JobParameters(Collections.singletonMap("identifierType", new JobParameter<>(identifierType, String.class))));
StepScopeTestUtils.doInStepScope(stepExecution, () -> {
var identifier = new ItemIdentifier("duplicateIdentifier");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@
}
],
"cost": {
"listUnitPrice": 2.0,
"listUnitPriceElectronic": 2.0,
"currency": "USD",
"discount": 10.0,
"discountType": "percentage",
"quantityPhysical": 1,
"quantityElectronic": 1,
"poLineEstimatedPrice": 1.8
},
"details": {
Expand Down
Loading

0 comments on commit d67353b

Please sign in to comment.