001 /* 002 * Copyright 2011 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 */ 016 package org.kuali.kfs.module.purap.document.web.struts; 017 018 import java.io.ByteArrayInputStream; 019 import java.io.ByteArrayOutputStream; 020 import java.io.InputStream; 021 import java.io.StringBufferInputStream; 022 023 import javax.servlet.ServletOutputStream; 024 import javax.servlet.http.HttpServletRequest; 025 import javax.servlet.http.HttpServletResponse; 026 027 import org.apache.commons.io.IOUtils; 028 import org.apache.commons.lang.StringUtils; 029 import org.apache.commons.lang.math.RandomUtils; 030 import org.apache.struts.action.ActionForm; 031 import org.apache.struts.action.ActionForward; 032 import org.apache.struts.action.ActionMapping; 033 import org.apache.struts.upload.FormFile; 034 import org.kuali.kfs.module.purap.batch.ElectronicInvoiceInputFileType; 035 import org.kuali.kfs.module.purap.businessobject.ElectronicInvoice; 036 import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItem; 037 import org.kuali.kfs.module.purap.document.PurchaseOrderDocument; 038 import org.kuali.kfs.module.purap.document.service.PurchaseOrderService; 039 import org.kuali.kfs.module.purap.util.ElectronicInvoiceUtils; 040 import org.kuali.kfs.sys.KFSConstants; 041 import org.kuali.kfs.sys.batch.service.BatchInputFileService; 042 import org.kuali.kfs.sys.context.SpringContext; 043 import org.kuali.kfs.vnd.businessobject.PaymentTermType; 044 import org.kuali.rice.kns.exception.AuthorizationException; 045 import org.kuali.rice.kns.service.DateTimeService; 046 import org.kuali.rice.kns.service.KualiConfigurationService; 047 import org.kuali.rice.kns.util.GlobalVariables; 048 import org.kuali.rice.kns.util.KualiDecimal; 049 import org.kuali.rice.kns.web.struts.action.KualiAction; 050 051 /** 052 * Struts Action for printing Purap documents outside of a document action 053 */ 054 public class ElectronicInvoiceTestAction extends KualiAction { 055 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ElectronicInvoiceTestAction.class); 056 057 private static final String AREA_C0DE = "areaCode"; 058 private static final String PHONE_NUMBER = "phoneNumber"; 059 060 /** 061 * @see org.kuali.rice.kns.web.struts.action.KualiAction#checkAuthorization(org.apache.struts.action.ActionForm, java.lang.String) 062 * 063 * Only allow users to test eInvoicing in the test environment 064 */ 065 @Override 066 protected void checkAuthorization(ActionForm form, String methodToCall) throws AuthorizationException { 067 if (SpringContext.getBean(KualiConfigurationService.class).isProductionEnvironment()) { 068 //this process is not available for production 069 throw new AuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalName(), methodToCall, this.getClass().getSimpleName()); 070 } 071 } 072 073 @Override 074 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 075 DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class); 076 077 checkAuthorization(form, ""); 078 079 //get parameters - are we doing upload xml or create based on PO? 080 String action = request.getParameter("action"); 081 082 String currDate = ElectronicInvoiceUtils.getDateDisplayText(dateTimeService.getCurrentDate()); // getting date in kfs format 083 084 if ("postXML".equalsIgnoreCase(action)) { 085 // get the file and send the contents to the eInvoice mechanism and display the results 086 ElectronicInvoiceTestForm rejectForm = (ElectronicInvoiceTestForm) form; 087 FormFile xmlFile = rejectForm.getXmlFile(); 088 if (xmlFile != null) { 089 if (!StringUtils.isEmpty(xmlFile.getFileName())) { 090 if (xmlFile.getFileName().endsWith(".xml")) { 091 092 BatchInputFileService batchInputFileService = SpringContext.getBean(BatchInputFileService.class); 093 ElectronicInvoiceInputFileType batchType = SpringContext.getBean(ElectronicInvoiceInputFileType.class); 094 095 byte[] fileByteContent = IOUtils.toByteArray(xmlFile.getInputStream()); 096 097 Object parsedObject = batchInputFileService.parse(batchType, fileByteContent); 098 ElectronicInvoice eInvoice = (ElectronicInvoice)parsedObject; 099 eInvoice.setFileName(xmlFile.getFileName()); 100 101 if (parsedObject != null) { 102 boolean validateSuccessful = batchInputFileService.validate(batchType, parsedObject); 103 104 if (validateSuccessful) { 105 InputStream saveStream = new ByteArrayInputStream(fileByteContent); 106 batchInputFileService.save(GlobalVariables.getUserSession().getPerson(), batchType, ""+RandomUtils.nextInt(), saveStream, parsedObject); 107 } 108 } 109 } else { 110 throw new RuntimeException("Invalid file type " + xmlFile.getFileName()); 111 } 112 } else { 113 throw new RuntimeException("Invalid file name " + xmlFile.getFileName()); 114 } 115 } else { 116 throw new RuntimeException("Error getting xml file"); 117 } 118 } else if ("returnXML".equalsIgnoreCase(action)) { 119 120 String poDocNumber = request.getParameter("poDocNumber"); 121 122 LOG.info("Generating xml for the po - " + poDocNumber); 123 124 PurchaseOrderService poService = SpringContext.getBean(PurchaseOrderService.class); 125 PurchaseOrderDocument po = null; 126 try{ 127 po = poService.getPurchaseOrderByDocumentNumber(poDocNumber); 128 }catch(Exception e){ 129 throw e; 130 } 131 132 response.setHeader("Cache-Control", "max-age=30"); 133 response.setContentType("application/xml"); 134 135 StringBuffer sbContentDispValue = new StringBuffer(); 136 String useJavascript = request.getParameter("useJavascript"); 137 if (useJavascript == null || useJavascript.equalsIgnoreCase("false")) { 138 sbContentDispValue.append("attachment"); 139 } 140 else { 141 sbContentDispValue.append("inline"); 142 } 143 StringBuffer sbFilename = new StringBuffer(); 144 sbFilename.append("PO_"); 145 sbFilename.append(poDocNumber); 146 sbFilename.append(".xml"); 147 sbContentDispValue.append("; filename="); 148 sbContentDispValue.append(sbFilename); 149 150 response.setHeader("Content-disposition", sbContentDispValue.toString()); 151 152 153 // lookup the PO and fill in the XML will valid data 154 155 if (po != null) { 156 157 String duns = ""; 158 if (po.getVendorDetail() != null){ 159 duns = StringUtils.defaultString(po.getVendorDetail().getVendorDunsNumber()); 160 } 161 162 String vendorNumber = po.getVendorDetail().getVendorNumber(); 163 164 String eInvoiceFile = 165 166 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 167 "\n<!-- ******Testing tool generated XML****** Version 1.2." + 168 "\n\n Generated On " + currDate + " for PO " + po.getPurapDocumentIdentifier() + " (Doc# " + poDocNumber + ") -->\n\n" + 169 "<!-- All the cXML attributes are junk values -->\n" + 170 "<cXML payloadID=\"200807260401062080.964@eai002\"\n" + 171 " timestamp=\"2008-07-26T04:01:06-08:00\"\n" + 172 " version=\"1.2.014\" xml:lang=\"en\" \n" + 173 " xmlns=\"http://www.kuali.org/kfs/purap/electronicInvoice\" \n" + 174 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + 175 " <Header>\n" + 176 " <From>\n" + 177 " <Credential domain=\"DUNS\">\n" + 178 " <Identity>" + duns + "</Identity> <!-- DUNS number from PO Vendor " + vendorNumber + "-->\n" + 179 " </Credential>\n" + 180 " </From>\n" + 181 " <To>\n" + 182 " <Credential domain=\"NetworkId\">\n" + 183 " <Identity>" + "IU" + "</Identity> <!-- Hardcoded --> \n" + 184 " </Credential>\n" + 185 " </To>\n" + 186 " <Sender>\n" + 187 " <Credential domain=\"DUNS\">\n" + 188 " <Identity>" + duns + "</Identity> <!-- DUNS number from PO Vendor " + vendorNumber + "-->\n" + 189 " </Credential>\n" + 190 " <UserAgent/>\n" + 191 " </Sender>\n" + 192 " </Header>\n" + 193 " <Request deploymentMode=\"production\">\n" + 194 " <InvoiceDetailRequest>\n" + 195 " <InvoiceDetailRequestHeader\n" + 196 " invoiceDate=\"" + currDate + "\" invoiceID=\"" + RandomUtils.nextInt() + "\" operation=\"new\" purpose=\"standard\"> <!-- invoiceID=Random unique Id, invoiceDate=Curr date -->\n" + 197 " <InvoiceDetailHeaderIndicator/>\n" + 198 " <InvoiceDetailLineIndicator/>\n" + 199 " <InvoicePartner>\n" + 200 getContactXMLChunk("billTo", po) + 201 " </InvoicePartner>\n" + 202 " <InvoicePartner>\n" + 203 " <Contact addressID=\"" + RandomUtils.nextInt() + "\" role=\"remitTo\"> <!-- Vendor address -->\n" + 204 " <Name xml:lang=\"en\">\n" + 205 " " + po.getVendorName() + "\n" + 206 " </Name>\n" + 207 " <PostalAddress>\n" + 208 " <Street>" + StringUtils.defaultString(po.getVendorLine1Address()) + "</Street>\n" + 209 " <Street>" + StringUtils.defaultString(po.getVendorLine2Address()) + "</Street>\n" + 210 " <City>" + StringUtils.defaultString(po.getVendorCityName()) + "</City>\n" + 211 " <State>" + StringUtils.defaultString(po.getVendorStateCode()) + "</State>\n" + 212 " <PostalCode>" + StringUtils.defaultString(po.getVendorPostalCode()) + "</PostalCode>\n" + 213 " <Country isoCountryCode=\"" + StringUtils.defaultString(po.getVendorCountryCode()) + "\">\n" + 214 " " + StringUtils.defaultString(po.getVendorCountry().getPostalCountryName()) + "\n" + 215 " </Country>\n" + 216 " </PostalAddress>\n" + 217 " </Contact>\n" + 218 " </InvoicePartner>\n" + 219 getDeliveryAddressXMLChunk("shipTo",po) + 220 getPaymentTermXML(po) + 221 " </InvoiceDetailRequestHeader>\n" + 222 " <InvoiceDetailOrder>\n" + 223 " <InvoiceDetailOrderInfo>\n" + 224 " <OrderReference\n" + 225 " orderDate=\"" + ElectronicInvoiceUtils.getDateDisplayText(dateTimeService.getCurrentDate()) + "\" orderID=\"" + po.getPurapDocumentIdentifier() + "\"> <!--orderDate=Curr date,orderID=PO#-->\n" + 226 " <DocumentReference payloadID=\"NA\" /> <!--HardCoded-->\n" + 227 " </OrderReference>\n" + 228 " </InvoiceDetailOrderInfo>\n" + 229 " <!-- No junk values in Items-->\n"; 230 231 for (int i = 0; i < po.getItems().size(); i++) { 232 PurchaseOrderItem item = (PurchaseOrderItem)po.getItem(i); 233 if (!item.getItemType().isAdditionalChargeIndicator()){ 234 eInvoiceFile = eInvoiceFile + getPOItemXMLChunk((PurchaseOrderItem)po.getItem(i)); 235 } 236 } 237 238 KualiDecimal totalDollarAmt = po.getTotalDollarAmount() == null ? KualiDecimal.ZERO : po.getTotalDollarAmount(); 239 eInvoiceFile = eInvoiceFile + 240 241 " </InvoiceDetailOrder>\n" + 242 " <InvoiceDetailSummary>\n" + 243 " <SubtotalAmount>\n" + 244 " <Money currency=\"USD\">" + po.getTotalPreTaxDollarAmount() + "</Money>\n" + 245 " </SubtotalAmount>\n" + 246 " <Tax>\n" + 247 " <Money currency=\"USD\">" + po.getTotalTaxAmount() + "</Money>\n" + 248 " <Description xml:lang=\"en\">Total Tax</Description>\n" + 249 " </Tax>\n" + 250 " <SpecialHandlingAmount>\n" + 251 " <Money currency=\"USD\">0.00</Money>\n" + 252 " </SpecialHandlingAmount>\n" + 253 " <ShippingAmount>\n" + 254 " <Money currency=\"USD\">0.00</Money>\n" + 255 " </ShippingAmount>\n" + 256 " <GrossAmount>\n" + 257 " <Money currency=\"USD\">" + totalDollarAmt + "</Money>\n" + 258 " </GrossAmount>\n" + 259 " <InvoiceDetailDiscount>\n" + 260 " <Money currency=\"USD\">0.00</Money>\n" + 261 " </InvoiceDetailDiscount>\n" + 262 " <NetAmount>\n" + 263 " <Money currency=\"USD\">" + totalDollarAmt + "</Money>\n" + 264 " </NetAmount>\n" + 265 " <DepositAmount>\n" + 266 " <Money currency=\"USD\">0.00</Money>\n" + 267 " </DepositAmount>\n" + 268 " <DueAmount>\n" + 269 " <Money currency=\"USD\">" + totalDollarAmt + "</Money>\n" + 270 " </DueAmount>\n" + 271 " </InvoiceDetailSummary>\n" + 272 " </InvoiceDetailRequest>\n" + 273 " </Request>\n" + 274 "</cXML>"; 275 276 // response.setContentLength(eInvoiceFile.length()); 277 278 ServletOutputStream sos; 279 280 sos = response.getOutputStream(); 281 282 ByteArrayOutputStream baOutStream = new ByteArrayOutputStream(); 283 StringBufferInputStream inStream = new StringBufferInputStream(eInvoiceFile); 284 convert(baOutStream, inStream); 285 // 286 // baOutStream.flush(); 287 response.setContentLength(baOutStream.size()); 288 289 // ServletOutputStream sosTemp = response.getOutputStream(); 290 baOutStream.writeTo(sos); 291 sos.flush(); 292 293 return null; 294 } 295 } 296 297 return mapping.findForward(KFSConstants.MAPPING_BASIC); 298 } 299 300 private String getPaymentTermXML(PurchaseOrderDocument po){ 301 String returnXML = ""; 302 303 PaymentTermType paymentTerm = null; 304 if (po.getVendorDetail() != null){ 305 paymentTerm = po.getVendorDetail().getVendorPaymentTerms(); 306 } 307 308 if (paymentTerm != null){ 309 if (paymentTerm.getVendorNetDueNumber() != null){ 310 returnXML = 311 " <InvoiceDetailPaymentTerm payInNumberOfDays=\"" + paymentTerm.getVendorNetDueNumber().toString() + "\" percentageRate=\"0\" />\n"; 312 }else if (paymentTerm.getVendorPaymentTermsPercent() != null){ 313 returnXML = 314 " <InvoiceDetailPaymentTerm payInNumberOfDays=\"0\" percentageRate=\"" + paymentTerm.getVendorPaymentTermsPercent() + "\" />\n"; 315 } 316 317 } 318 319 return returnXML; 320 } 321 322 private String getPOItemXMLChunk(PurchaseOrderItem item){ 323 324 String itemUnitPrice = item.getItemUnitPrice() == null ? 325 StringUtils.EMPTY : 326 item.getItemUnitPrice().toString(); 327 328 String subTotal = StringUtils.EMPTY; 329 if (item.getItemUnitPrice() != null && item.getItemQuantity() != null){ 330 subTotal = (item.getItemUnitPrice().multiply(item.getItemQuantity().bigDecimalValue())).toString(); 331 } 332 333 return 334 335 " <InvoiceDetailItem invoiceLineNumber=\"" + item.getItemLineNumber() + "\"\n" + 336 " quantity=\"" + item.getItemQuantity() + "\">\n" + 337 " <UnitOfMeasure>" + item.getItemUnitOfMeasureCode() + "</UnitOfMeasure>\n" + 338 " <UnitPrice>\n" + 339 " <Money currency=\"USD\">" + itemUnitPrice + "</Money>\n" + 340 " </UnitPrice>\n" + 341 " <InvoiceDetailItemReference lineNumber=\"" + item.getItemLineNumber() + "\">\n" + 342 " <ItemID>\n" + 343 " <SupplierPartID>" + StringUtils.defaultString(item.getItemCatalogNumber()) + "</SupplierPartID>\n" + 344 " </ItemID>\n" + 345 " <Description xml:lang=\"en\">" + StringUtils.defaultString(item.getItemDescription()) + "</Description>\n" + 346 " </InvoiceDetailItemReference>\n" + 347 " <SubtotalAmount>\n" + 348 " <Money currency=\"USD\" >" + subTotal + "</Money>\n" + 349 " </SubtotalAmount>\n" + 350 " </InvoiceDetailItem>\n"; 351 352 } 353 354 private String getDeliveryAddressXMLChunk(String addressType, 355 PurchaseOrderDocument po){ 356 357 String deliveryDate = ""; 358 if (po.getDeliveryRequiredDate() != null){ 359 deliveryDate = ElectronicInvoiceUtils.getDateDisplayText(po.getDeliveryRequiredDate()); 360 } 361 362 String returnXML = ""; 363 364 if (StringUtils.isNotEmpty(deliveryDate)){ 365 returnXML = returnXML + " <InvoiceDetailShipping shippingDate=\"" + deliveryDate + "\"> <!--Delivery reqd date -->\n"; 366 }else{ 367 returnXML = returnXML + " <InvoiceDetailShipping> <!-- shipTo address same as billTo-->\n"; 368 } 369 370 returnXML = returnXML + 371 getContactXMLChunk("shipTo",po) + 372 " </InvoiceDetailShipping>\n"; 373 374 return returnXML; 375 376 } 377 378 private String getContactXMLChunk(String addressType, 379 PurchaseOrderDocument po){ 380 381 String returnXML = 382 383 " <Contact addressID=\"" + RandomUtils.nextInt() + "\" role=\"" + addressType + "\"> <!-- addressId=Random Unique Id -->\n" + 384 " <Name xml:lang=\"en\">" + po.getDeliveryCampusCode() + " - " + po.getDeliveryBuildingName() + "</Name> <!-- Format:CampusCode - Bldg Nm -->\n" + 385 " <PostalAddress>\n" + 386 " <Street>" + StringUtils.defaultString(po.getDeliveryBuildingLine1Address()) + "</Street>\n" + 387 " <Street>" + StringUtils.defaultString(po.getDeliveryBuildingLine2Address()) + "</Street>\n" + 388 " <City>" + StringUtils.defaultString(po.getDeliveryCityName()) + "</City>\n" + 389 " <State>" + StringUtils.defaultString(po.getDeliveryStateCode()) + "</State>\n" + 390 " <PostalCode>" + StringUtils.defaultString(po.getDeliveryPostalCode()) + "</PostalCode>\n" + 391 " <Country isoCountryCode=\"" + StringUtils.defaultString(po.getDeliveryCountryCode()) + "\">\n" + 392 " " + StringUtils.defaultString(po.getDeliveryCountryName()) + "\n" + 393 " </Country>\n" + 394 " </PostalAddress>\n"; 395 396 if (StringUtils.isNotEmpty(po.getDeliveryToEmailAddress())){ 397 returnXML = returnXML + 398 " <Email name=\"" + po.getDeliveryToEmailAddress() + "\">" + po.getDeliveryToEmailAddress() + "</Email>\n"; 399 } 400 401 if (StringUtils.isNotEmpty(po.getDeliveryToPhoneNumber())){ 402 returnXML = returnXML + 403 " <Phone name=\"" + po.getDeliveryToPhoneNumber() + "\">\n" + 404 " <TelephoneNumber>\n" + 405 " <CountryCode isoCountryCode=\"US\">1</CountryCode>\n" + 406 " <AreaOrCityCode>" + getPhoneNumber(AREA_C0DE, po.getDeliveryToPhoneNumber()) + "</AreaOrCityCode>\n" + 407 " <Number>" + getPhoneNumber(PHONE_NUMBER, po.getDeliveryToPhoneNumber()) + "</Number>\n" + 408 " </TelephoneNumber>\n" + 409 " </Phone>\n"; 410 } 411 412 returnXML = returnXML + 413 // " <URL name=\"sampleCompanyURL\">www.abc.com</URL>\n" + 414 " </Contact>\n"; 415 416 417 return returnXML; 418 419 } 420 421 private String getPhoneNumber(String whichPart,String phNo){ 422 423 if (StringUtils.isEmpty(phNo)){ 424 return StringUtils.EMPTY; 425 } 426 427 if (StringUtils.equals(whichPart,AREA_C0DE)){ 428 return phNo.substring(0,3); 429 }else if (StringUtils.equals(whichPart,PHONE_NUMBER)){ 430 return phNo.substring(3,phNo.length()); 431 } 432 433 return StringUtils.EMPTY; 434 } 435 436 private boolean convert(java.io.OutputStream out, java.io.InputStream in) { 437 try { 438 int r; 439 while ((r=in.read())!=-1) { 440 out.write(r); 441 } 442 return true; 443 }catch (java.io.IOException ioe) { 444 return false; 445 } 446 } 447 448 } 449