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