001/*
002 * Copyright 2007 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.ole.module.purap.edi;
017
018import com.lowagie.text.DocumentException;
019import org.apache.commons.logging.Log;
020import org.apache.commons.logging.LogFactory;
021import org.kuali.ole.module.purap.PurapConstants;
022import org.kuali.ole.module.purap.businessobject.PurApItem;
023import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
024import org.kuali.ole.module.purap.exception.PurError;
025import org.kuali.ole.module.purap.util.PurApDateFormatUtils;
026import org.kuali.ole.select.businessobject.OlePurchaseOrderItem;
027import org.kuali.ole.select.lookup.DocLookupSearch;
028import org.kuali.ole.select.lookup.DocLookupServiceImpl;
029import org.kuali.ole.sys.context.SpringContext;
030import org.kuali.rice.core.api.datetime.DateTimeService;
031import org.kuali.rice.krad.util.ObjectUtils;
032
033import java.io.*;
034import java.text.SimpleDateFormat;
035import java.util.*;
036
037/**
038 * Base class to handle Edi for purchase order documents.
039 */
040public class PurchaseOrderEdi {
041    private static Log LOG = LogFactory.getLog(PurchaseOrderEdi.class);
042
043    private DateTimeService dateTimeService;
044
045
046    public PurchaseOrderEdi() {
047    }
048
049
050    /**
051     * Invokes the createEdiFile method to create a EDI document and saves it into a file
052     * which name and location are specified in the file.
053     *
054     * @param po           The PurchaseOrderDocument to be used to create the EDI.
055     * @param file         The file containing some of the parameters information needed by the EDI for example, the EDI file name and EDI file location, purchasing director name, etc.
056     * @param isRetransmit The boolean to indicate whether this is for a retransmit purchase order document.
057     * @param environment  The current environment used (e.g. DEV if it is a development environment).
058     */
059    public boolean saveEdi(PurchaseOrderDocument po, PurApItem item, String file) {
060        if (LOG.isInfoEnabled()) {
061            LOG.info("saveEdi() started for po number " + po.getPurapDocumentIdentifier());
062        }
063
064        try {
065            createEdiFile(po, item, file);
066            if (LOG.isDebugEnabled()) {
067                LOG.debug("saveEdi() completed for po number " + po.getPurapDocumentIdentifier());
068            }
069        } catch (DocumentException de) {
070            LOG.error("saveEdi() DocumentException: " + de.getMessage(), de);
071            throw new PurError("Document Exception when trying to save a Purchase Order EDI", de);
072        } catch (FileNotFoundException f) {
073            LOG.error("saveEdi() FileNotFoundException: " + f.getMessage(), f);
074            throw new PurError("FileNotFound Exception when trying to save a Purchase Order EDI", f);
075        } catch (IOException i) {
076            LOG.error("saveEdi() IOException: " + i.getMessage(), i);
077            throw new PurError("IO Exception when trying to save a Purchase Order EDI", i);
078        } catch (Exception t) {
079            LOG.error("saveEdi() EXCEPTION: " + t.getMessage(), t);
080            throw new PurError("Exception when trying to save a Purchase Order EDI", t);
081        }
082        return true;
083    }
084
085
086    /**
087     * This method is for generate a unique reference number for a PO
088     *
089     * @return String
090     * @throws Exception
091     */
092    private String generateReferenceNumber() throws Exception {
093        UUID referenceNumber = UUID.randomUUID();
094        return referenceNumber.toString();
095    }
096
097
098    /**
099     * Create an EDI file using the given input parameters.
100     *
101     * @param po   The PurchaseOrderDocument to be used to create the EDI.
102     * @param file The EDI document whose margins have already been set.
103     * @throws Exception
104     */
105    private void createEdiFile(PurchaseOrderDocument po, PurApItem item, String file) throws Exception {
106        Writer writer = null;
107        StringBuffer text = new StringBuffer();
108        try {
109
110            LOG.debug("EDI File creation started");
111            List<OlePurchaseOrderItem> purchaseOrderItemList = new ArrayList<OlePurchaseOrderItem>();
112            String itemIdentifier = item.getItemIdentifier().toString();
113            Map map = new HashMap();
114            map.put("itemIdentifier", itemIdentifier);
115            DocLookupServiceImpl impl = SpringContext.getBean(DocLookupServiceImpl.class, "docLookupService");
116            OlePurchaseOrderItem olePurchaseOrderItem = null;
117            impl.setLookupDao(new DocLookupSearch());
118            try {
119                List<OlePurchaseOrderItem> searchResults = (List) impl.findCollectionBySearchHelper(OlePurchaseOrderItem.class, map, true);
120                for (OlePurchaseOrderItem poItem : searchResults) {
121                    purchaseOrderItemList.add(poItem);
122                }
123                olePurchaseOrderItem = purchaseOrderItemList.get(0);
124            } catch (Exception exception) {
125                LOG.error("*****Exception in createEdiFile()******: No matching data found in the docstore " + exception.getMessage());
126            }
127
128            int lineCount = 0;
129            String uniqueRefNumber = generateReferenceNumber();
130            text.append("UNH+" + uniqueRefNumber + "ORDERS:D:96A:UN:EAN008'");
131            text.append(System.getProperty("line.separator"));
132            lineCount++;
133            String statusCode = "220";
134            if (po.getApplicationDocumentStatus() != null && po.getApplicationDocumentStatus().equalsIgnoreCase(PurapConstants.PurchaseOrderStatuses.APPDOC_RETIRED_VERSION)) {
135                statusCode = "230";
136            }
137            text.append("BGM+" + statusCode + "+" + po.getPurapDocumentIdentifier().toString() + "+9'");
138            text.append(System.getProperty("line.separator"));
139            lineCount++;
140            String orderDate = "";
141
142            SimpleDateFormat sdf = PurApDateFormatUtils.getSimpleDateFormat(PurapConstants.NamedDateFormats.KUALI_SIMPLE_DATE_FORMAT_2);
143            if (po.getPurchaseOrderInitialOpenTimestamp() != null) {
144                orderDate = sdf.format(po.getPurchaseOrderInitialOpenTimestamp());
145            } else {
146                // This date isn't set until the first time this document is printed, so will be null the first time; use today's date.
147                orderDate = sdf.format(getDateTimeService().getCurrentSqlDate());
148            }
149
150            SimpleDateFormat formatter = new SimpleDateFormat("MM-dd-yyyy");
151            Date date = formatter.parse(orderDate);
152            String formattedDate = formatter.format(date);
153
154            Date newDate = formatter.parse(formattedDate);
155            formatter = new SimpleDateFormat("yyMMdd");
156            formattedDate = formatter.format(newDate);
157
158            Calendar calendar = Calendar.getInstance();
159            calendar.setTime(date);
160            int century = (calendar.get(Calendar.YEAR) / 100) + 1;
161
162            text.append("DTM+137:" + century + formattedDate + ":102'");
163            text.append(System.getProperty("line.separator"));
164            lineCount++;
165            text.append("NAD+SU+++" + getSupplierDetails(po) + "'");
166            text.append(System.getProperty("line.separator"));
167            lineCount++;
168            text.append("NAD+BY+++" + getBillingDetails(po) + "'");
169            text.append(System.getProperty("line.separator"));
170            lineCount++;
171            text.append("NAD+DP+++" + getDeliveryDetails(po) + "'");
172            text.append(System.getProperty("line.separator"));
173            lineCount++;
174            if (po.getVendorCustomerNumber() != null && po.getVendorCustomerNumber().length() > 0) {
175                text.append("RFF+API:" + po.getVendorCustomerNumber() + "'");
176                text.append(System.getProperty("line.separator"));
177                lineCount++;
178            }
179
180            //text.append("CUX+2:"+"USD"+":9'");
181            //text.append(System.getProperty("line.separator"));
182            text.append("LIN+" + "1'");
183            text.append(System.getProperty("line.separator"));
184            lineCount++;
185            text.append("PIA+5+" + "9781444334609" + ":IB'");
186            text.append(System.getProperty("line.separator"));
187            lineCount++;
188            if (olePurchaseOrderItem != null && olePurchaseOrderItem.getDocData() != null) {
189                if (olePurchaseOrderItem.getDocData().getTitle() != null && olePurchaseOrderItem.getDocData().getTitle().length() > 0) {
190                    text.append("IMD+L+050+:::" + olePurchaseOrderItem.getDocData().getTitle() + "'");
191                    text.append(System.getProperty("line.separator"));
192                    lineCount++;
193                }
194                if (olePurchaseOrderItem.getDocData().getPlaceOfPublication() != null && olePurchaseOrderItem.getDocData().getPlaceOfPublication().length() > 0) {
195                    text.append("IMD+L+110+:::" + olePurchaseOrderItem.getDocData().getPlaceOfPublication() + "'");
196                    text.append(System.getProperty("line.separator"));
197                    lineCount++;
198                }
199                if (olePurchaseOrderItem.getDocData().getAuthor() != null && olePurchaseOrderItem.getDocData().getAuthor().length() > 0) {
200                    text.append("IMD+L+009+:::" + olePurchaseOrderItem.getDocData().getAuthor() + "'");
201                    text.append(System.getProperty("line.separator"));
202                    lineCount++;
203                }
204                if (olePurchaseOrderItem.getDocData().getPublicationDate() != null && olePurchaseOrderItem.getDocData().getPublicationDate().length() > 0) {
205                    text.append("IMD+L+170+:::" + olePurchaseOrderItem.getDocData().getPublicationDate() + "'");
206                    text.append(System.getProperty("line.separator"));
207                    lineCount++;
208                }
209                if (olePurchaseOrderItem.getDocData().getPublisher() != null && olePurchaseOrderItem.getDocData().getPublisher().length() > 0) {
210                    text.append("IMD+L+109+:::" + olePurchaseOrderItem.getDocData().getPublisher() + "'");
211                    text.append(System.getProperty("line.separator"));
212                    lineCount++;
213                }
214            }
215
216            text.append("QTY+21:" + item.getItemQuantity() + "'");
217            text.append(System.getProperty("line.separator"));
218            lineCount++;
219            text.append("PRI+AAE:" + "33" + ":SRP'");
220            text.append(System.getProperty("line.separator"));
221            lineCount++;
222            text.append("UNS+S'");
223            text.append(System.getProperty("line.separator"));
224            lineCount++;
225            text.append("CNT+2:1'");
226            text.append(System.getProperty("line.separator"));
227            lineCount++;
228            lineCount++;
229            text.append("UNT+" + lineCount + "+" + uniqueRefNumber + ":'");
230
231            File filePath = new File(file);
232            writer = new BufferedWriter(new FileWriter(filePath));
233            writer.write(text.toString());
234            LOG.debug("EDI File created");
235        } finally {
236            try {
237                if (writer != null) {
238                    writer.close();
239                }
240            } catch (IOException e) {
241                e.printStackTrace();
242            }
243        }
244
245    }
246
247
248    /**
249     * This method is to get the Supplier details
250     *
251     * @param po
252     * @return String
253     */
254    public String getSupplierDetails(PurchaseOrderDocument po) {
255        String str = (po.getVendorName() != null && po.getVendorName().length() > 0 ? po.getVendorName() + "+" : "") +
256                (po.getVendorAttentionName() != null && po.getVendorAttentionName().length() > 0 ? "ATTN: " + po.getVendorAttentionName() + "+" : "") +
257                (po.getVendorLine1Address() != null && po.getVendorLine1Address().length() > 0 ? po.getVendorLine1Address() + "+" : "") +
258                (po.getVendorCityName() != null && po.getVendorCityName().length() > 0 ? po.getVendorCityName() + "+" : "") +
259                (po.getVendorStateCode() != null && po.getVendorStateCode().length() > 0 ? po.getVendorStateCode() + "+" : "") +
260                (po.getVendorPostalCode() != null && po.getVendorPostalCode().length() > 0 ? po.getVendorPostalCode() + "+" : "") +
261                (po.getVendorCountryCode() != null && po.getVendorCountryCode().length() > 0 ? po.getVendorCountryCode() : "");
262        return str;
263
264    }
265
266
267    /**
268     * This method is to get the billing details
269     *
270     * @param po
271     * @return String
272     */
273    public String getBillingDetails(PurchaseOrderDocument po) {
274        String str = (po.getBillingName() != null && po.getBillingName().length() > 0 ? po.getBillingName() + "+" : "") +
275                (po.getBillingLine1Address() != null && po.getBillingLine1Address().length() > 0 ? po.getBillingLine1Address() + "+" : "") +
276                (po.getBillingLine2Address() != null && po.getBillingLine2Address().length() > 0 ? po.getBillingLine2Address() + "+" : "") +
277                (po.getBillingCityName() != null && po.getBillingCityName().length() > 0 ? po.getBillingCityName() + "+" : "") +
278                (po.getBillingStateCode() != null && po.getBillingStateCode().length() > 0 ? po.getBillingStateCode() + "+" : "") +
279                (po.getBillingPhoneNumber() != null && po.getBillingPhoneNumber().length() > 0 ? po.getBillingPhoneNumber() + "+" : "") +
280                (po.getBillingPostalCode() != null && po.getBillingPostalCode().length() > 0 ? po.getBillingPostalCode() + "+" : "") +
281                (po.getBillingCountryCode() != null && po.getBillingCountryCode().length() > 0 ? po.getBillingCountryCode() : "");
282        return str;
283
284    }
285
286
287    /**
288     * This method is to get the delivery details
289     *
290     * @param po
291     * @return String
292     */
293    public String getDeliveryDetails(PurchaseOrderDocument po) {
294        String str = (po.getDeliveryToName() != null && po.getDeliveryToName().length() > 0 ? po.getDeliveryToName() + "+" : "") +
295                (po.getDeliveryBuildingRoomNumber() != null && po.getDeliveryBuildingRoomNumber().length() > 0 ? "Room # " + po.getDeliveryBuildingRoomNumber() + "+" : "") +
296                (po.getDeliveryBuildingLine1Address() != null && po.getDeliveryBuildingLine1Address().length() > 0 ? po.getDeliveryBuildingLine1Address() + "+" : "") +
297                (po.getDeliveryCityName() != null && po.getDeliveryCityName().length() > 0 ? po.getDeliveryCityName() + "+" : "") +
298                (po.getDeliveryStateCode() != null && po.getDeliveryStateCode().length() > 0 ? po.getDeliveryStateCode() + "+" : "") +
299                (po.getDeliveryPostalCode() != null && po.getDeliveryPostalCode().length() > 0 ? po.getDeliveryPostalCode() + "+" : "") +
300                (po.getDeliveryCountryCode() != null && po.getDeliveryCountryCode().length() > 0 ? po.getDeliveryCountryCode() : "");
301        return str;
302
303    }
304
305
306    public DateTimeService getDateTimeService() {
307        if (ObjectUtils.isNull(dateTimeService)) {
308            this.dateTimeService = SpringContext.getBean(DateTimeService.class);
309        }
310        return this.dateTimeService;
311    }
312
313}