Index: build.gradle =================================================================== diff -u -r0eaa6374a2fd97a507f8597b10b2c289a1b82299 -re436b1e9ee540c61bbd4599d5b37ed8340dc8634 --- build.gradle (.../build.gradle) (revision 0eaa6374a2fd97a507f8597b10b2c289a1b82299) +++ build.gradle (.../build.gradle) (revision e436b1e9ee540c61bbd4599d5b37ed8340dc8634) @@ -76,7 +76,8 @@ testCompile "org.grails:grails-plugin-testing" compile 'lemans:xml-json:0.11' - compile 'org.apache.httpcomponents:httpclient:4.2.1' + compile 'org.apache.httpcomponents:httpcore:4.4.1' + compile 'org.apache.httpcomponents:httpclient:4.5' compile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.2' provided 'net.sourceforge.jtds:jtds:1.3.1' @@ -86,6 +87,17 @@ compile 'com.lemans.grails.plugins:lemans-rest:0.1.0c' testCompile 'com.lemans.grails.plugins:lemans-testing:0.1.0a' + + // Jackson Core + compile 'com.fasterxml.jackson.core:jackson-core:2.14.2' + + // Jackson Databind + compile 'com.fasterxml.jackson.core:jackson-databind:2.14.2' + + // Jackson Dataformat XML + compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2' + compile 'com.fasterxml.jackson.core:jackson-annotations:2.12.5' + } bootRun { Index: grails-app/conf/spring/resources.groovy =================================================================== diff -u -r72d1a0b21fab8d5614ee5d363e14ee58b798b969 -re436b1e9ee540c61bbd4599d5b37ed8340dc8634 --- grails-app/conf/spring/resources.groovy (.../resources.groovy) (revision 72d1a0b21fab8d5614ee5d363e14ee58b798b969) +++ grails-app/conf/spring/resources.groovy (.../resources.groovy) (revision e436b1e9ee540c61bbd4599d5b37ed8340dc8634) @@ -5,10 +5,24 @@ Environment current = Environment.current if (current != Environment.PRODUCTION) { authServiceContext(String, 'http://services3.dev.lemanscorp.com/auth-service/verifyRequest') + quotesRootUri(String, "https://vm-rmx-int-lb-pub.lemanscorp.com:8005") + quotesApiKey(String, "290487cf-d2fd-4620-8d4f-d5ad05fd99fe") + quotesClientDataSource(String, "lemans-integration.sandbox.operations.dynamics.com") } else { authServiceContext(org.springframework.jndi.JndiObjectFactoryBean) { jndiName = 'java:comp/env/authServiceContext' } + quotesRootUri(org.springframework.jndi.JndiObjectFactoryBean) { + jndiName = 'java:comp/env/quotesRootUri' + } + + quotesApiKey(org.springframework.jndi.JndiObjectFactoryBean) { + jndiName = 'java:comp/env/quotesApiKey' + } + + quotesClientDataSource(org.springframework.jndi.JndiObjectFactoryBean) { + jndiName = 'java:comp/env/quotesClientDataSource' + } } } Index: grails-app/controllers/com/lemans/prfeed/MasterFeedController.groovy =================================================================== diff -u -r0b19cecd6ac5c13138469b109eb3a864ff09a3ff -re436b1e9ee540c61bbd4599d5b37ed8340dc8634 --- grails-app/controllers/com/lemans/prfeed/MasterFeedController.groovy (.../MasterFeedController.groovy) (revision 0b19cecd6ac5c13138469b109eb3a864ff09a3ff) +++ grails-app/controllers/com/lemans/prfeed/MasterFeedController.groovy (.../MasterFeedController.groovy) (revision e436b1e9ee540c61bbd4599d5b37ed8340dc8634) @@ -21,12 +21,8 @@ } else { try { - JSONObject xmlJSONObj = XML.toJSONArray(productFeedService.masterFeedXml(criteria)) - if (!('true' == params.doNotRender)) { - String jsonPrettyPrintString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR) - render(contentType: 'application/json', text: jsonPrettyPrintString) - } - xmlJSONObj + String jsonPrettyPrintString = productFeedService.masterFeedXml(criteria, params.dealerCode, params.partNumber) + render(contentType: 'application/json', text: jsonPrettyPrintString) } catch (SQLException x) { response.status = 500 render toJson(message: x.message) Index: grails-app/services/com/lemans/prfeed/ProductFeedService.groovy =================================================================== diff -u -r0b19cecd6ac5c13138469b109eb3a864ff09a3ff -re436b1e9ee540c61bbd4599d5b37ed8340dc8634 --- grails-app/services/com/lemans/prfeed/ProductFeedService.groovy (.../ProductFeedService.groovy) (revision 0b19cecd6ac5c13138469b109eb3a864ff09a3ff) +++ grails-app/services/com/lemans/prfeed/ProductFeedService.groovy (.../ProductFeedService.groovy) (revision e436b1e9ee540c61bbd4599d5b37ed8340dc8634) @@ -1,10 +1,17 @@ package com.lemans.prfeed +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.dataformat.xml.XmlMapper +import com.lemans.prfeed.rmx.PricingResponseService import com.lemans.services.LemansService import grails.transaction.Transactional +import org.json.JSONObject +import org.json.XML @Transactional(readOnly = true) class ProductFeedService extends LemansService { + + def pricingManagerService private static final String MASTER_FEED_SQL = '''EXEC dbo.spFeedContent @@ -28,5 +35,17 @@ * * @return XML */ - String masterFeedXml(List criteria) { queryForXml(MASTER_FEED_SQL, criteria) } + String masterFeedXml(List criteria, String dealerCode, String partNumber) { + String response = queryForXml(MASTER_FEED_SQL, criteria) + JSONObject xmlJSONObj = XML.toJSONArray(response) + String jsonPrettyPrintString = xmlJSONObj.toString(4) + if (dealerCode && partNumber) { + ObjectMapper objectMapper = new ObjectMapper() + Map data = objectMapper.readValue(jsonPrettyPrintString, Map.class) + PricingResponseService[] result = pricingManagerService.calculatePrice(dealerCode, [data.root.domain.semantic.parts[0][0][0][0]]) + data.root.domain.semantic.parts[0][0][0][0].netPrice = result[0]?.documentLines?.lineFields?.netPrice ? result[0]?.documentLines?.lineFields?.netPrice[0] : 0 + return objectMapper.writeValueAsString(data) + } + jsonPrettyPrintString + } } Index: grails-app/services/com/lemans/prfeed/rmx/PricingManagerService.groovy =================================================================== diff -u --- grails-app/services/com/lemans/prfeed/rmx/PricingManagerService.groovy (revision 0) +++ grails-app/services/com/lemans/prfeed/rmx/PricingManagerService.groovy (revision e436b1e9ee540c61bbd4599d5b37ed8340dc8634) @@ -0,0 +1,67 @@ +package com.lemans.prfeed.rmx + +import com.fasterxml.jackson.databind.ObjectMapper +import org.apache.http.client.config.RequestConfig +import org.apache.http.conn.ConnectTimeoutException +import org.apache.http.impl.client.CloseableHttpClient +import org.apache.http.impl.client.HttpClients +import org.springframework.http.HttpEntity +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.client.RestTemplate + +import javax.annotation.Resource + +@Transactional +class PricingManagerService { + + @Resource(name = 'quotesApiKey') + def quotesApiKey + + @Resource(name = 'quotesRootUri') + def quotesRootUri + + @Resource(name = 'quotesClientDataSource') + def quotesClientDataSource + + PricingResponseService[] calculatePrice(String dealerCode, List lines) { + RestTemplate restTemplate = new RestTemplate() + HttpHeaders headers = new HttpHeaders() + try { + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(20000) // Connection timeout in milliseconds + .setSocketTimeout(20000) // Socket timeout in milliseconds + .build() + + CloseableHttpClient httpClient = HttpClients.custom() + .setDefaultRequestConfig(requestConfig) + .build() + + restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)) + List result = lines.collect { part -> new PricingRequestService(dealerCode, [part]) } + String payload = new ObjectMapper().writer().writeValueAsString(result) + log.debug('payload to to sent' + payload) + headers.set("X-API-KEY", quotesApiKey) + headers.setContentType(MediaType.APPLICATION_JSON) + HttpEntity entity = new HttpEntity<>(payload, headers) + String url = quotesRootUri + '/api/pricingEngine/price/priceCollection?ClientDataSource=' + quotesClientDataSource + ResponseEntity response = restTemplate.exchange(url, org.springframework.http.HttpMethod.POST, entity, String.class) + return PricingResponseService.Parser.parserMethod(response.getBody()) + } catch (SocketTimeoutException | ConnectTimeoutException e) { + log.error('HttpClient Timeout Exception: ' + e.message) + PricingResponseService pricingResponseService = new PricingResponseService() + pricingResponseService.handlePricingError('error', 'Timeout', 'Timeout while connecting to the server(RMx), please contact helpdesk') + return pricingResponseService + } + catch(Exception e) { + log.error(e.message) + PricingResponseService pricingResponseService = new PricingResponseService() + pricingResponseService.handlePricingError('error', 'Invalid pricing', 'Error while calculating yourDealerPrice, please contact helpdesk') + return pricingResponseService + } + } +} + Index: grails-app/services/com/lemans/prfeed/rmx/PricingRequestService.groovy =================================================================== diff -u --- grails-app/services/com/lemans/prfeed/rmx/PricingRequestService.groovy (revision 0) +++ grails-app/services/com/lemans/prfeed/rmx/PricingRequestService.groovy (revision e436b1e9ee540c61bbd4599d5b37ed8340dc8634) @@ -0,0 +1,82 @@ +package com.lemans.prfeed.rmx + +import com.fasterxml.jackson.annotation.JsonFormat +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonProperty + +class PricingRequestService { + + @JsonProperty("custVend") + CustomerVendor customerVendor + List documentLines + String company = "LMC" + String currency = "USD" + String documentType = "Unspecified" + + PricingRequestService(String dealerCode, List parts) { + this.customerVendor = new CustomerVendor(dealerCode) + this.documentLines = parts.collect { DocumentLine.forPartAndToday(it) } + } + + static class CustomerVendor { + @JsonProperty("code") + String code + String entityType = "Customer" + + CustomerVendor(String code) { + this.code = code + this.entityType = entityType + } + } + + static class DocumentLine { + @JsonProperty("lineFields") + LineFields lineFields + + DocumentLine(LineFields lineFields) { + this.lineFields = lineFields + } + + static DocumentLine forPartAndToday(Map part) { + new DocumentLine( + new LineFields( + effectiveDate: new Date(), + product: new LineFields.ProductSpec(part.partNumber), + lineUnitOfMeasureCode: part.uom, + costPrice: part.cost, + unitOfMeasure: new LineFields.UnitOfMeasure(part.uom ?: 'EA') + ) + ) + } + + static class LineFields { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss") + Date effectiveDate + ProductSpec product + int quantity = 1 + BigDecimal costPrice + String lineUnitOfMeasureCode = "" + String lineAction = "Unspecified" + String lineType = "StandardLine" + static final String COMMON_UOM = "EA" + @JsonInclude(JsonInclude.Include.NON_EMPTY) + UnitOfMeasure unitOfMeasure + + static class UnitOfMeasure { + String unitOfMeasureCode + + UnitOfMeasure(String unitOfMeasureCode) { + this.unitOfMeasureCode = unitOfMeasureCode + } + } + + static class ProductSpec { + String code + + ProductSpec(String code) { + this.code = code + } + } + } + } +} Index: grails-app/services/com/lemans/prfeed/rmx/PricingResponseService.groovy =================================================================== diff -u --- grails-app/services/com/lemans/prfeed/rmx/PricingResponseService.groovy (revision 0) +++ grails-app/services/com/lemans/prfeed/rmx/PricingResponseService.groovy (revision e436b1e9ee540c61bbd4599d5b37ed8340dc8634) @@ -0,0 +1,149 @@ +package com.lemans.prfeed.rmx + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.databind.ObjectMapper +import groovy.util.logging.Log4j + +@JsonIgnoreProperties(ignoreUnknown = true) +@Log4j +class PricingResponseService { + + @JsonProperty("documentLines") + private List documentLines + + private HandleError handleError + + List getDocumentLines() { + return documentLines + } + + void setDocumentLines(List documentLines) { + this.documentLines = documentLines + } + + @JsonIgnoreProperties(ignoreUnknown = true) + HandleError getHandleError() { + return handleError + } + + void setHandleError(HandleError handleError) { + this.handleError = handleError + } + + public void handlePricingError(String type, String code, String message) { + HandleError newError = new HandleError(type, code, message) + setHandleError(newError) + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class DocumentLine { + + @JsonProperty("lineFields") + private LineFields lineFields + + LineFields getLineFields() { + return lineFields + } + + void setLineFields(LineFields lineFields) { + this.lineFields = lineFields + } + + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class LineFields { + + @JsonProperty("product") + private Product product + + @JsonProperty("netPrice") + private double netPrice + + double getNetPrice() { + return netPrice + } + + void setNetPrice(double netPrice) { + this.netPrice = netPrice + } + + Product getProduct() { + return product + } + + void setProduct(Product product) { + this.product = product + } + + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Product { + + @JsonProperty("code") + private String code + + String getCode() { + return code + } + + void setCode(String code) { + this.code = code + } + } + + public static class Parser { + static PricingResponseService[] parserMethod(String json) { + try { + ObjectMapper mapper = new ObjectMapper() + log.debug('json' + json) + PricingResponseService[] documents = mapper.readValue(json, PricingResponseService[].class) + List documentList = Arrays.asList(documents) + for (PricingResponseService document : documentList) { + for (DocumentLine documentLine : document.getDocumentLines()) { + for (LineFields lineFields : documentLine.getLineFields()) { + lineFields.netPrice = lineFields.getNetPrice() + } + } + } + documents + } catch (Exception e) { + log.error(e.message) + PricingResponseService pricingResponseService = new PricingResponseService() + pricingResponseService.handlePricingError('error', 'Parsing error','Error while parsing yourDealerPrice, please contact helpdesk') + return pricingResponseService + } + } + } + + public static class HandleError { + String getType() { + return type + } + + void setType(String type) { + this.type = type + } + + String getMessage() { + return message + } + + void setMessage(String message) { + this.message = message + } + + String type + String code + String message + + HandleError(String type, String code,String message) { + this.type = type + this.code = code + this.message = message + } + } +}