/** * *************************************************************************** * Copyright (c) 2010 Qcadoo Limited * Project: Qcadoo Framework * Version: 1.2.0 * * This file is part of Qcadoo. * * Qcadoo is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************** */ package com.qcadoo.mes.integration.efcSimple.parser; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringWriter; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import org.apache.commons.io.IOUtils; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; import com.google.common.base.Charsets; import com.qcadoo.mes.integration.cfcSimple.importer.model.ParsedOrder; import com.qcadoo.mes.integration.cfcSimple.importer.model.ParsedOrderItem; import com.qcadoo.mes.integration.cfcSimple.importer.model.ParsedProduct; import com.qcadoo.mes.integration.cfcSimple.importer.parser.IntegrationParseMessages; import com.qcadoo.mes.integration.cfcSimple.importer.parser.IntegrationParser; import com.qcadoo.mes.integration.cfcSimple.importer.parser.IntegrationParserException; import com.qcadoo.mes.integration.cfcSimple.importer.parser.IntegrationParserResult; import com.qcadoo.mes.integration.cfcSimple.importer.parser.IntegrationParserUtils; public class EnovaParser implements IntegrationParser { private static final String TYPE_L = "type"; private static final String UNCHECKED = "unchecked"; private static final Namespace DEFAULT_NAMESPACE = Namespace.getNamespace("http://www.soneta.pl/schema/business"); public enum ProductType { PRODUCT, SERVICE, GOOD, COMPONENT; }; public enum StateType { UNCONFIRMED, CONFIRMED, APPROVED; } private enum Nodes { ORDER("DokumentHandlowy"), PRODUCT("Towar"), UNIT("Jednostka"), ORDER_ID("id"), ORDER_NR("Numer"), ORDER_NR_FULL("Pelny"), ORDER_STATE( "Stan"), PRODUCT_GUID("guid"), PRODUCT_CODE("Kod"), PRODUCT_TYPE("Typ"), PRODUCT_NAME("Nazwa"), PRODUCT_EAN("EAN"), PRODUCT_UNIT( "Jednostka"), UNIT_GUID("guid"), UNIT_CODE("Kod"), ORDER_ITEMS("Pozycje"), ORDER_ITEM("PozycjaDokHandlowego"), PRODUCT_QUANTITY( "IloscZasobuValue"), PRODUCT_IDENT("Ident"); private Nodes(final String name) { this.name = name; } private String name; public String getName() { return name; } } @Override public IntegrationParserResult parse(final InputStream stream) throws IntegrationParserException { Map<String, String> productGuidToCodesMap = new HashMap<String, String>(); IntegrationParserResult result = new IntegrationParserResult(); try { InputStream decodedStream = decodeInputStream(stream); SAXBuilder builder = new SAXBuilder(); Document document = builder.build(decodedStream); Element root = document.getRootElement(); @SuppressWarnings(UNCHECKED) List<Element> orders = root.getChildren(Nodes.ORDER.getName(), DEFAULT_NAMESPACE); @SuppressWarnings(UNCHECKED) List<Element> products = root.getChildren(Nodes.PRODUCT.getName(), DEFAULT_NAMESPACE); @SuppressWarnings(UNCHECKED) List<Element> units = root.getChildren(Nodes.UNIT.getName(), DEFAULT_NAMESPACE); if (orders.isEmpty() && products.isEmpty()) { throw IntegrationParserException .createParseError(EnovaIntegrationParseMessages.NO_DATA_TO_IMPORT.getMessageKey()); } if (units.isEmpty()) { throw IntegrationParserException.createParseError(EnovaIntegrationParseMessages.NO_UNITS.getMessageKey()); } for (Element element : products) { result.addParsedProduct(parseProduct(element, units, productGuidToCodesMap)); } for (Element order : orders) { ParsedOrder parsedOrder = parseOrder(order); @SuppressWarnings(UNCHECKED) List<Element> orderProducts = order.getChild(Nodes.ORDER_ITEMS.getName(), DEFAULT_NAMESPACE).getChildren( Nodes.ORDER_ITEM.getName(), DEFAULT_NAMESPACE); for (Element orderProduct : orderProducts) { if (checkIfProductWasDefined(orderProduct, products)) { parsedOrder.addItem(getOrderItem(orderProduct, productGuidToCodesMap)); } } result.addParsedOrder(parsedOrder); } performFinalValidation(result); } catch (JDOMException e) { throw IntegrationParserException.createParseError(e, EnovaIntegrationParseMessages.JDOM_EXCEPTION.getMessageKey(), e.getMessage()); } catch (IOException e) { throw IntegrationParserException.createParseError(e, IntegrationParseMessages.IO_EXCEPTION.getMessageKey(), e.getMessage()); } return result; } private void performFinalValidation(final IntegrationParserResult parseResult) throws IntegrationParserException { Set<String> definedProducts = new HashSet<String>(); for (ParsedProduct product : parseResult.getProducts()) { definedProducts.add(product.getIdentificationCode()); } for (ParsedOrder order : parseResult.getOrders()) { for (ParsedOrderItem item : order.getItems()) { if (!definedProducts.contains(item.getProductIdentificationCode())) { throw IntegrationParserException.createParseError( IntegrationParseMessages.PRODUCT_NOT_DEFINED.getMessageKey(), item.getProductIdentificationCode()); } } } } private InputStream decodeInputStream(final InputStream stream) throws IOException { Reader reader = new InputStreamReader(stream, Charsets.UTF_16); StringWriter writer = new StringWriter(); IOUtils.copy(reader, writer); String xml = writer.toString(); return new ByteArrayInputStream(xml.getBytes(Charsets.UTF_16)); } private boolean checkIfProductWasDefined(final Element orderProduct, final List<Element> products) { for (Element product : products) { if (product.getAttribute(Nodes.PRODUCT_GUID.getName()).getValue() .equals(orderProduct.getChild(Nodes.PRODUCT.getName(), DEFAULT_NAMESPACE).getValue())) { return true; } } return false; } private ParsedOrderItem getOrderItem(final Element orderProduct, final Map<String, String> productGuidToCodesMap) throws IntegrationParserException { IntegrationParserUtils.checkRequiredParameter(orderProduct.getChild(Nodes.PRODUCT.getName(), DEFAULT_NAMESPACE), "towar"); IntegrationParserUtils.checkRequiredParameter(orderProduct.getChild(Nodes.PRODUCT_QUANTITY.getName(), DEFAULT_NAMESPACE), "IloscZasobuValue"); IntegrationParserUtils.checkRequiredParameter(orderProduct.getChild(Nodes.PRODUCT_IDENT.getName(), DEFAULT_NAMESPACE), "Ident"); ParsedOrderItem orderItem = new ParsedOrderItem(); String productGuid = orderProduct.getChild("Towar", DEFAULT_NAMESPACE).getValue(); orderItem.setProductIdentificationCode(productGuidToCodesMap.get(productGuid)); orderItem.setField("quantity", orderProduct.getChild(Nodes.PRODUCT_QUANTITY.getName(), DEFAULT_NAMESPACE).getValue()); orderItem.setField("number", orderProduct.getChild(Nodes.PRODUCT_IDENT.getName(), DEFAULT_NAMESPACE).getValue()); return orderItem; } private ParsedOrder parseOrder(final Element order) throws IntegrationParserException { Attribute id = order.getAttribute(Nodes.ORDER_ID.getName()); Element drawDate = order.getChild("Data", DEFAULT_NAMESPACE); Element shipmentDate = order.getChild("DataOperacji", DEFAULT_NAMESPACE); Element orderNr = order.getChild(Nodes.ORDER_NR.getName(), DEFAULT_NAMESPACE); Element fullOrderNr = order.getChild(Nodes.ORDER_NR.getName(), DEFAULT_NAMESPACE).getChild(Nodes.ORDER_NR_FULL.getName(), DEFAULT_NAMESPACE); Element orderState = order.getChild(Nodes.ORDER_STATE.getName(), DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(id, "Product"); IntegrationParserUtils.checkRequiredParameter(drawDate, "Date"); IntegrationParserUtils.checkRequiredParameter(shipmentDate, "Shipment date"); IntegrationParserUtils.checkRequiredParameter(orderNr, "Order number"); IntegrationParserUtils.checkRequiredParameter(fullOrderNr, "Full order number"); IntegrationParserUtils.checkRequiredParameter(orderState, "Order state"); ParsedOrder parsedOrder = new ParsedOrder(); parsedOrder.setField("name", id.getValue()); parsedOrder.setField("drawDate", drawDate.getValue()); parsedOrder.setField("realizationDate", shipmentDate.getValue()); parsedOrder.setField("clientName", getClientName(getContractorDetails(order))); parsedOrder.setField("clientAddress", getClientAddress(getContractorDetails(order))); parsedOrder.setField("number", fullOrderNr.getValue()); if ("potwierdzone".equals(order.getChild(Nodes.ORDER_STATE.getName(), DEFAULT_NAMESPACE).getValue() .toLowerCase(Locale.getDefault()))) { parsedOrder.setField("state", StateType.CONFIRMED.toString()); } else if ("zatwierdzony".equals(order.getChild(Nodes.ORDER_STATE.getName(), DEFAULT_NAMESPACE).getValue() .toLowerCase(Locale.getDefault()))) { parsedOrder.setField("state", StateType.APPROVED.toString()); } else { parsedOrder.setField("state", StateType.UNCONFIRMED.toString()); } return parsedOrder; } private String getClientAddress(final Element contractor) throws IntegrationParserException { if (contractor != null) { Element addressElement = contractor.getChild("Adres", DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(addressElement, "Address"); Element street = addressElement.getChild("Ulica", DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(street, "Street"); Element houseNumber = addressElement.getChild("NrDomu", DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(houseNumber, "House number"); Element postalCode = addressElement.getChild("KodPocztowy", DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(postalCode, "Postal code"); Element town = addressElement.getChild("Miejscowosc", DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(town, "Town"); return street.getValue() + " " + houseNumber.getValue() + " " + addressElement.getChild("NrLokalu", DEFAULT_NAMESPACE).getValue() + "\n" + postalCode.getValue().substring(0, 2) + "-" + postalCode.getValue().substring(2) + " " + town.getValue(); } return ""; } private String getClientName(final Element contractor) throws IntegrationParserException { if (contractor != null) { IntegrationParserUtils.checkRequiredParameter(contractor.getChild("Nazwa", DEFAULT_NAMESPACE), "Contractor name"); return contractor.getChild("Nazwa", DEFAULT_NAMESPACE).getValue(); } return ""; } private Element getContractorDetails(final Element order) { Element contractorSection = order.getChild("Dane_kontrahentów", DEFAULT_NAMESPACE); @SuppressWarnings(UNCHECKED) List<Element> contractors = contractorSection.getChildren(); for (Element contractor : contractors) { if ("DaneKontrahenta".equals(contractor.getName()) && "0".equals(contractor.getChild("Typ", DEFAULT_NAMESPACE).getValue())) { return contractor; } } return null; } private ParsedProduct parseProduct(final Element element, final List<Element> units, final Map<String, String> productGuidToCodesMap) throws IntegrationParserException { ParsedProduct product = new ParsedProduct(); Attribute productGuid = element.getAttribute(Nodes.PRODUCT_GUID.getName()); IntegrationParserUtils.checkRequiredParameter(productGuid, "Product guid not present"); Element code = element.getChild(Nodes.PRODUCT_CODE.getName(), DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(code, "Product code not present"); productGuidToCodesMap.put(productGuid.getValue(), code.getValue()); product.setIdentificationCode(code.getValue()); Element type = element.getChild(Nodes.PRODUCT_TYPE.getName(), DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(type, "Type not present"); if ("Produkt".equals(type.getValue())) { product.setField(TYPE_L, ProductType.PRODUCT.toString()); } else if ("Usługa".equals(type.getValue())) { product.setField(TYPE_L, ProductType.SERVICE.toString()); } else if ("Towar".equals(type.getValue())) { product.setField(TYPE_L, ProductType.GOOD.toString()); } else if ("Składnik".equals(type.getValue())) { product.setField(TYPE_L, ProductType.COMPONENT.toString()); } Element productName = element.getChild(Nodes.PRODUCT_NAME.getName(), DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(productName, "Product name not present"); product.setField("name", productName.getValue()); Element ean = element.getChild(Nodes.PRODUCT_EAN.getName(), DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(productName, "Product name not present"); product.setField("ean", ean.getValue()); Element unit = element.getChild(Nodes.PRODUCT_UNIT.getName(), DEFAULT_NAMESPACE); IntegrationParserUtils.checkRequiredParameter(productName, "Unit name not present"); product.setField("unit", getUnitForUnitGuidOrId(units, unit.getValue())); return product; } private String getUnitForUnitGuidOrId(final List<Element> units, final String unit) throws IntegrationParserException { for (Element element : units) { IntegrationParserUtils.checkRequiredParameter(element.getAttribute(Nodes.UNIT_GUID.getName()), "Guid for unit not present"); IntegrationParserUtils.checkRequiredParameter(element.getChild(Nodes.UNIT_CODE.getName(), DEFAULT_NAMESPACE), "Unit code not present"); if (unit.equals(element.getAttribute(Nodes.UNIT_GUID.getName()).getValue()) || unit.equals(element.getAttribute("id").getValue())) { return element.getChild(Nodes.UNIT_CODE.getName(), DEFAULT_NAMESPACE).getValue(); } } return null; } }