1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.module.purap.document.web.struts;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.apache.commons.lang.math.RandomUtils;
20 import org.apache.struts.action.ActionForm;
21 import org.apache.struts.action.ActionForward;
22 import org.apache.struts.action.ActionMapping;
23 import org.kuali.ole.module.purap.PurapKeyConstants;
24 import org.kuali.ole.module.purap.PurapPropertyConstants;
25 import org.kuali.ole.module.purap.businessobject.PurchaseOrderItem;
26 import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
27 import org.kuali.ole.module.purap.document.service.PurchaseOrderService;
28 import org.kuali.ole.module.purap.util.ElectronicInvoiceUtils;
29 import org.kuali.ole.sys.OLEConstants;
30 import org.kuali.ole.sys.context.SpringContext;
31 import org.kuali.ole.vnd.businessobject.PaymentTermType;
32 import org.kuali.rice.core.api.datetime.DateTimeService;
33 import org.kuali.rice.core.api.util.RiceConstants;
34 import org.kuali.rice.core.api.util.type.KualiDecimal;
35 import org.kuali.rice.kns.web.struts.action.KualiAction;
36 import org.kuali.rice.krad.exception.AuthorizationException;
37 import org.kuali.rice.krad.service.DocumentService;
38 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
39 import org.kuali.rice.krad.util.GlobalVariables;
40 import org.kuali.rice.krad.util.KRADUtils;
41
42 import javax.servlet.ServletOutputStream;
43 import javax.servlet.http.HttpServletRequest;
44 import javax.servlet.http.HttpServletResponse;
45 import java.io.ByteArrayOutputStream;
46 import java.io.StringBufferInputStream;
47 import java.util.List;
48
49
50
51
52 public class ElectronicInvoiceTestAction extends KualiAction {
53 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ElectronicInvoiceTestAction.class);
54
55 private static final String AREA_C0DE = "areaCode";
56 private static final String PHONE_NUMBER = "phoneNumber";
57
58 protected static volatile DocumentService documentService;
59
60
61
62
63
64 @Override
65 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
66
67
68 String methodToCall = findMethodToCall(form, request);
69 if (StringUtils.equals(methodToCall, "generate")) {
70 return generate(mapping, form, request, response);
71 }
72 return mapping.findForward(OLEConstants.MAPPING_BASIC);
73 }
74
75
76
77
78
79
80 @Override
81 protected void checkAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
82 if (KRADUtils.isProductionEnvironment()) {
83
84 throw new AuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalName(), methodToCall, this.getClass().getSimpleName());
85 }
86 }
87
88
89
90
91 public ActionForward generate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
92 checkAuthorization(form, "");
93
94 ElectronicInvoiceTestForm testForm = (ElectronicInvoiceTestForm) form;
95 String poDocNumber = testForm.getPoDocNumber();
96 LOG.info("Generating Electronic Invoice XML file for Purchase Order Document " + poDocNumber);
97 PurchaseOrderService poService = SpringContext.getBean(PurchaseOrderService.class);
98 PurchaseOrderDocument po = null;
99
100 if (StringUtils.isBlank(poDocNumber)) {
101 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_DOCUMENT_NUMBER, PurapKeyConstants.ERROR_ELECTRONIC_INVOICE_GENERATION_PURCHASE_ORDER_NUMBER_EMPTY, new String[]{poDocNumber});
102 return mapping.findForward(RiceConstants.MAPPING_BASIC);
103 }
104 if (!getDocumentService().documentExists(poDocNumber)) {
105 GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_DOCUMENT_NUMBER, PurapKeyConstants.ERROR_ELECTRONIC_INVOICE_GENERATION_PURCHASE_ORDER_DOES_NOT_EXIST, poDocNumber);
106 return mapping.findForward(RiceConstants.MAPPING_BASIC);
107 }
108
109 try {
110 po = poService.getPurchaseOrderByDocumentNumber(poDocNumber);
111 } catch (Exception e) {
112 throw e;
113 }
114
115 response.setHeader("Cache-Control", "max-age=30");
116 response.setContentType("application/xml");
117 StringBuffer sbContentDispValue = new StringBuffer();
118 String useJavascript = request.getParameter("useJavascript");
119 if (useJavascript == null || useJavascript.equalsIgnoreCase("false")) {
120 sbContentDispValue.append("attachment");
121 } else {
122 sbContentDispValue.append("inline");
123 }
124 StringBuffer sbFilename = new StringBuffer();
125 sbFilename.append("PO_");
126 sbFilename.append(poDocNumber);
127 sbFilename.append(".xml");
128 sbContentDispValue.append("; filename=");
129 sbContentDispValue.append(sbFilename);
130 response.setHeader("Content-disposition", sbContentDispValue.toString());
131
132
133 if (po != null) {
134 String duns = "";
135 if (po.getVendorDetail() != null) {
136 duns = StringUtils.defaultString(po.getVendorDetail().getVendorDunsNumber());
137 }
138
139 DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class);
140 String currDate = ElectronicInvoiceUtils.getDateDisplayText(dateTimeService.getCurrentDate());
141 String vendorNumber = po.getVendorDetail().getVendorNumber();
142
143 String eInvoiceFile =
144 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
145 "\n<!-- ******Testing tool generated XML****** Version 1.2." +
146 "\n\n Generated On " + currDate + " for PO " + po.getPurapDocumentIdentifier() + " (Doc# " + poDocNumber + ") -->\n\n" +
147 "<!-- All the cXML attributes are junk values -->\n" +
148 "<cXML payloadID=\"200807260401062080.964@eai002\"\n" +
149 " timestamp=\"2008-07-26T04:01:06-08:00\"\n" +
150 " version=\"1.2.014\" xml:lang=\"en\" \n" +
151 " xmlns=\"http://www.kuali.org/ole/purap/electronicInvoice\" \n" +
152 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
153 " <Header>\n" +
154 " <From>\n" +
155 " <Credential domain=\"DUNS\">\n" +
156 " <Identity>" + duns + "</Identity> <!-- DUNS number from PO Vendor " + vendorNumber + "-->\n" +
157 " </Credential>\n" +
158 " </From>\n" +
159 " <To>\n" +
160 " <Credential domain=\"NetworkId\">\n" +
161 " <Identity>" + "IU" + "</Identity> <!-- Hardcoded --> \n" +
162 " </Credential>\n" +
163 " </To>\n" +
164 " <Sender>\n" +
165 " <Credential domain=\"DUNS\">\n" +
166 " <Identity>" + duns + "</Identity> <!-- DUNS number from PO Vendor " + vendorNumber + "-->\n" +
167 " </Credential>\n" +
168 " <UserAgent/>\n" +
169 " </Sender>\n" +
170 " </Header>\n" +
171 " <Request deploymentMode=\"production\">\n" +
172 " <InvoiceDetailRequest>\n" +
173 " <InvoiceDetailRequestHeader\n" +
174 " invoiceDate=\"" + currDate + "\" invoiceID=\"" + RandomUtils.nextInt() + "\" operation=\"new\" purpose=\"standard\"> <!-- invoiceID=Random unique Id, invoiceDate=Curr date -->\n" +
175 " <InvoiceDetailHeaderIndicator/>\n" +
176 " <InvoiceDetailLineIndicator/>\n" +
177 " <InvoicePartner>\n" +
178 getContactXMLChunk("billTo", po) +
179 " </InvoicePartner>\n" +
180 " <InvoicePartner>\n" +
181 " <Contact addressID=\"" + RandomUtils.nextInt() + "\" role=\"remitTo\"> <!-- Vendor address -->\n" +
182 " <Name xml:lang=\"en\">\n" +
183 " " + po.getVendorName() + "\n" +
184 " </Name>\n" +
185 " <PostalAddress>\n" +
186 " <Street>" + StringUtils.defaultString(po.getVendorLine1Address()) + "</Street>\n" +
187 " <Street>" + StringUtils.defaultString(po.getVendorLine2Address()) + "</Street>\n" +
188 " <City>" + StringUtils.defaultString(po.getVendorCityName()) + "</City>\n" +
189 " <State>" + StringUtils.defaultString(po.getVendorStateCode()) + "</State>\n" +
190 " <PostalCode>" + StringUtils.defaultString(po.getVendorPostalCode()) + "</PostalCode>\n" +
191 " <Country isoCountryCode=\"" + StringUtils.defaultString(po.getVendorCountryCode()) + "\">\n" +
192 " " + StringUtils.defaultString(po.getVendorCountry().getName()) + "\n" +
193 " </Country>\n" +
194 " </PostalAddress>\n" +
195 " </Contact>\n" +
196 " </InvoicePartner>\n" +
197 getDeliveryAddressXMLChunk("shipTo", po) +
198 getPaymentTermXML(po) +
199 " </InvoiceDetailRequestHeader>\n" +
200 " <InvoiceDetailOrder>\n" +
201 " <InvoiceDetailOrderInfo>\n" +
202 " <OrderReference\n" +
203 " orderDate=\"" + ElectronicInvoiceUtils.getDateDisplayText(dateTimeService.getCurrentDate()) + "\" orderID=\"" + po.getPurapDocumentIdentifier() + "\"> <!--orderDate=Curr date,orderID=PO#-->\n" +
204 " <DocumentReference payloadID=\"NA\" /> <!--HardCoded-->\n" +
205 " </OrderReference>\n" +
206 " </InvoiceDetailOrderInfo>\n" +
207 " <!-- No junk values in Items-->\n";
208
209 for (int i = 0; i < po.getItems().size(); i++) {
210 List items = po.getItems();
211 PurchaseOrderItem item = (PurchaseOrderItem) items.get(i);
212 if (!item.getItemType().isAdditionalChargeIndicator()) {
213 eInvoiceFile = eInvoiceFile + getPOItemXMLChunk(item);
214 }
215 }
216
217 KualiDecimal totalDollarAmt = po.getTotalDollarAmount() == null ? KualiDecimal.ZERO : po.getTotalDollarAmount();
218 eInvoiceFile = eInvoiceFile +
219
220 " </InvoiceDetailOrder>\n" +
221 " <InvoiceDetailSummary>\n" +
222 " <SubtotalAmount>\n" +
223 " <Money currency=\"USD\">" + po.getTotalPreTaxDollarAmount() + "</Money>\n" +
224 " </SubtotalAmount>\n" +
225 " <Tax>\n" +
226 " <Money currency=\"USD\">" + po.getTotalTaxAmount() + "</Money>\n" +
227 " <Description xml:lang=\"en\">Total Tax</Description>\n" +
228 " </Tax>\n" +
229 " <SpecialHandlingAmount>\n" +
230 " <Money currency=\"USD\">0.00</Money>\n" +
231 " </SpecialHandlingAmount>\n" +
232 " <ShippingAmount>\n" +
233 " <Money currency=\"USD\">0.00</Money>\n" +
234 " </ShippingAmount>\n" +
235 " <GrossAmount>\n" +
236 " <Money currency=\"USD\">" + totalDollarAmt + "</Money>\n" +
237 " </GrossAmount>\n" +
238 " <InvoiceDetailDiscount>\n" +
239 " <Money currency=\"USD\">0.00</Money>\n" +
240 " </InvoiceDetailDiscount>\n" +
241 " <NetAmount>\n" +
242 " <Money currency=\"USD\">" + totalDollarAmt + "</Money>\n" +
243 " </NetAmount>\n" +
244 " <DepositAmount>\n" +
245 " <Money currency=\"USD\">0.00</Money>\n" +
246 " </DepositAmount>\n" +
247 " <DueAmount>\n" +
248 " <Money currency=\"USD\">" + totalDollarAmt + "</Money>\n" +
249 " </DueAmount>\n" +
250 " </InvoiceDetailSummary>\n" +
251 " </InvoiceDetailRequest>\n" +
252 " </Request>\n" +
253 "</cXML>";
254
255 ServletOutputStream sos;
256 sos = response.getOutputStream();
257 ByteArrayOutputStream baOutStream = new ByteArrayOutputStream();
258 StringBufferInputStream inStream = new StringBufferInputStream(eInvoiceFile);
259 convert(baOutStream, inStream);
260 response.setContentLength(baOutStream.size());
261 baOutStream.writeTo(sos);
262 sos.flush();
263 }
264
265 return mapping.findForward(OLEConstants.MAPPING_BASIC);
266 }
267
268 private String getPaymentTermXML(PurchaseOrderDocument po) {
269 String returnXML = "";
270
271 PaymentTermType paymentTerm = null;
272 if (po.getVendorDetail() != null) {
273 paymentTerm = po.getVendorDetail().getVendorPaymentTerms();
274 }
275
276 if (paymentTerm != null) {
277 if (paymentTerm.getVendorNetDueNumber() != null) {
278 returnXML =
279 " <InvoiceDetailPaymentTerm payInNumberOfDays=\"" + paymentTerm.getVendorNetDueNumber().toString() + "\" percentageRate=\"0\" />\n";
280 } else if (paymentTerm.getVendorPaymentTermsPercent() != null) {
281 returnXML =
282 " <InvoiceDetailPaymentTerm payInNumberOfDays=\"0\" percentageRate=\"" + paymentTerm.getVendorPaymentTermsPercent() + "\" />\n";
283 }
284
285 }
286
287 return returnXML;
288 }
289
290 private String getPOItemXMLChunk(PurchaseOrderItem item) {
291
292 String itemUnitPrice = item.getItemUnitPrice() == null ?
293 StringUtils.EMPTY :
294 item.getItemUnitPrice().toString();
295
296 String subTotal = StringUtils.EMPTY;
297 if (item.getItemUnitPrice() != null && item.getItemQuantity() != null) {
298 subTotal = (item.getItemUnitPrice().multiply(item.getItemQuantity().bigDecimalValue())).toString();
299 }
300
301 return
302
303 " <InvoiceDetailItem invoiceLineNumber=\"" + item.getItemLineNumber() + "\"\n" +
304 " quantity=\"" + item.getItemQuantity() + "\">\n" +
305 " <UnitOfMeasure>" + item.getItemUnitOfMeasureCode() + "</UnitOfMeasure>\n" +
306 " <UnitPrice>\n" +
307 " <Money currency=\"USD\">" + itemUnitPrice + "</Money>\n" +
308 " </UnitPrice>\n" +
309 " <InvoiceDetailItemReference lineNumber=\"" + item.getItemLineNumber() + "\">\n" +
310 " <ItemID>\n" +
311 " <SupplierPartID>" + StringUtils.defaultString(item.getItemCatalogNumber()) + "</SupplierPartID>\n" +
312 " </ItemID>\n" +
313 " <Description xml:lang=\"en\">" + StringUtils.defaultString(item.getItemDescription()) + "</Description>\n" +
314 " </InvoiceDetailItemReference>\n" +
315 " <SubtotalAmount>\n" +
316 " <Money currency=\"USD\" >" + subTotal + "</Money>\n" +
317 " </SubtotalAmount>\n" +
318 " </InvoiceDetailItem>\n";
319
320 }
321
322 private String getDeliveryAddressXMLChunk(String addressType,
323 PurchaseOrderDocument po) {
324
325 String deliveryDate = "";
326 if (po.getDeliveryRequiredDate() != null) {
327 deliveryDate = ElectronicInvoiceUtils.getDateDisplayText(po.getDeliveryRequiredDate());
328 }
329
330 String returnXML = "";
331
332 if (StringUtils.isNotEmpty(deliveryDate)) {
333 returnXML += " <InvoiceDetailShipping shippingDate=\"" + deliveryDate + "\"> <!--Delivery reqd date -->\n";
334 } else {
335 returnXML += " <InvoiceDetailShipping> <!-- shipTo address same as billTo-->\n";
336 }
337 returnXML += getContactXMLChunk("shipTo", po) + " </InvoiceDetailShipping>\n";
338
339 return returnXML;
340
341 }
342
343 private String getContactXMLChunk(String addressType,
344 PurchaseOrderDocument po) {
345
346 String returnXML =
347
348 " <Contact addressID=\"" + RandomUtils.nextInt() + "\" role=\"" + addressType + "\"> <!-- addressId=Random Unique Id -->\n" +
349 " <Name xml:lang=\"en\">" + po.getDeliveryCampusCode() + " - " + po.getDeliveryBuildingName() + "</Name> <!-- Format:CampusCode - Bldg Nm -->\n" +
350 " <PostalAddress>\n" +
351 " <Street>" + StringUtils.defaultString(po.getDeliveryBuildingLine1Address()) + "</Street>\n" +
352 " <Street>" + StringUtils.defaultString(po.getDeliveryBuildingLine2Address()) + "</Street>\n" +
353 " <City>" + StringUtils.defaultString(po.getDeliveryCityName()) + "</City>\n" +
354 " <State>" + StringUtils.defaultString(po.getDeliveryStateCode()) + "</State>\n" +
355 " <PostalCode>" + StringUtils.defaultString(po.getDeliveryPostalCode()) + "</PostalCode>\n" +
356 " <Country isoCountryCode=\"" + StringUtils.defaultString(po.getDeliveryCountryCode()) + "\">\n" +
357 " " + StringUtils.defaultString(po.getDeliveryCountryName()) + "\n" +
358 " </Country>\n" +
359 " </PostalAddress>\n";
360
361 if (StringUtils.isNotEmpty(po.getDeliveryToEmailAddress())) {
362 returnXML += " <Email name=\"" + po.getDeliveryToEmailAddress() + "\">" + po.getDeliveryToEmailAddress() + "</Email>\n";
363 }
364
365 if (StringUtils.isNotEmpty(po.getDeliveryToPhoneNumber())) {
366 returnXML +=
367 " <Phone name=\"" + po.getDeliveryToPhoneNumber() + "\">\n" +
368 " <TelephoneNumber>\n" +
369 " <CountryCode isoCountryCode=\"US\">1</CountryCode>\n" +
370 " <AreaOrCityCode>" + getPhoneNumber(AREA_C0DE, po.getDeliveryToPhoneNumber()) + "</AreaOrCityCode>\n" +
371 " <Number>" + getPhoneNumber(PHONE_NUMBER, po.getDeliveryToPhoneNumber()) + "</Number>\n" +
372 " </TelephoneNumber>\n" +
373 " </Phone>\n";
374 }
375
376 returnXML += " </Contact>\n";
377 return returnXML;
378 }
379
380 private String getPhoneNumber(String whichPart, String phNo) {
381
382 if (StringUtils.isEmpty(phNo)) {
383 return StringUtils.EMPTY;
384 }
385
386 if (StringUtils.equals(whichPart, AREA_C0DE)) {
387 return phNo.substring(0, 3);
388 } else if (StringUtils.equals(whichPart, PHONE_NUMBER)) {
389 return phNo.substring(3, phNo.length());
390 }
391
392 return StringUtils.EMPTY;
393 }
394
395 private boolean convert(java.io.OutputStream out, java.io.InputStream in) {
396 try {
397 int r;
398 while ((r = in.read()) != -1) {
399 out.write(r);
400 }
401 return true;
402 } catch (java.io.IOException ioe) {
403 return false;
404 }
405 }
406
407
408
409
410 protected DocumentService getDocumentService() {
411 if (documentService == null) {
412 documentService = KRADServiceLocatorWeb.getDocumentService();
413 }
414 return documentService;
415 }
416 }