/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program 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, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.module.purap.document.web.struts;
import java.io.ByteArrayOutputStream;
import java.io.StringBufferInputStream;
import java.util.List;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.kuali.kfs.module.purap.PurapKeyConstants;
import org.kuali.kfs.module.purap.PurapPropertyConstants;
import org.kuali.kfs.module.purap.businessobject.PurchaseOrderItem;
import org.kuali.kfs.module.purap.document.PurchaseOrderDocument;
import org.kuali.kfs.module.purap.document.service.PurchaseOrderService;
import org.kuali.kfs.module.purap.util.ElectronicInvoiceUtils;
import org.kuali.kfs.sys.KFSConstants;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.kfs.vnd.businessobject.PaymentTermType;
import org.kuali.rice.core.api.datetime.DateTimeService;
import org.kuali.rice.core.api.util.RiceConstants;
import org.kuali.rice.core.api.util.type.KualiDecimal;
import org.kuali.rice.kns.web.struts.action.KualiAction;
import org.kuali.rice.krad.exception.AuthorizationException;
import org.kuali.rice.krad.service.DocumentService;
import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
import org.kuali.rice.krad.util.GlobalVariables;
import org.kuali.rice.krad.util.KRADUtils;
/**
* Struts Action for printing Purap documents outside of a document action
*/
public class ElectronicInvoiceTestAction extends KualiAction {
private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ElectronicInvoiceTestAction.class);
private static final String AREA_C0DE = "areaCode";
private static final String PHONE_NUMBER = "phoneNumber";
protected static volatile DocumentService documentService;
/**
* @see org.kuali.rice.kns.web.struts.action.KualiAction#execute(org.apache.struts.action.ActionMapping,
* org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
// TODO Uncomment the following code. This method doesn't need override.
// It's here as a temp get-around for a bug complaining method "generate" cannot be found
String methodToCall = findMethodToCall(form, request);
if (StringUtils.equals(methodToCall, "generate")) {
return generate(mapping, form, request, response);
}
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
/**
* @see org.kuali.rice.kns.web.struts.action.KualiAction#checkAuthorization(org.apache.struts.action.ActionForm, java.lang.String)
*
* Only allow users to test eInvoicing in the test environment
*/
@Override
protected void checkAuthorization(ActionForm form, String methodToCall) throws AuthorizationException {
if (KRADUtils.isProductionEnvironment()) {
//this process is not available for production
throw new AuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalName(), methodToCall, this.getClass().getSimpleName());
}
}
/**
* Generates Electronic Invoice xml file from a Purchase Order, for testing purpose only.
*/
public ActionForward generate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
checkAuthorization(form, "");
ElectronicInvoiceTestForm testForm = (ElectronicInvoiceTestForm)form;
String poDocNumber = testForm.getPoDocNumber();
LOG.info("Generating Electronic Invoice XML file for Purchase Order Document " + poDocNumber);
PurchaseOrderService poService = SpringContext.getBean(PurchaseOrderService.class);
PurchaseOrderDocument po = null;
if (StringUtils.isBlank(poDocNumber)) {
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_DOCUMENT_NUMBER, PurapKeyConstants.ERROR_ELECTRONIC_INVOICE_GENERATION_PURCHASE_ORDER_NUMBER_EMPTY, new String[] { poDocNumber} );
return mapping.findForward(RiceConstants.MAPPING_BASIC);
}
if (!getDocumentService().documentExists(poDocNumber)) {
GlobalVariables.getMessageMap().putError(PurapPropertyConstants.PURCHASE_ORDER_DOCUMENT_NUMBER, PurapKeyConstants.ERROR_ELECTRONIC_INVOICE_GENERATION_PURCHASE_ORDER_DOES_NOT_EXIST, poDocNumber);
return mapping.findForward(RiceConstants.MAPPING_BASIC);
}
try {
po = poService.getPurchaseOrderByDocumentNumber(poDocNumber);
}
catch (Exception e) {
throw e;
}
response.setHeader("Cache-Control", "max-age=30");
response.setContentType("application/xml");
StringBuffer sbContentDispValue = new StringBuffer();
String useJavascript = request.getParameter("useJavascript");
if (useJavascript == null || useJavascript.equalsIgnoreCase("false")) {
sbContentDispValue.append("attachment");
}
else {
sbContentDispValue.append("inline");
}
StringBuffer sbFilename = new StringBuffer();
sbFilename.append("PO_");
sbFilename.append(poDocNumber);
sbFilename.append(".xml");
sbContentDispValue.append("; filename=");
sbContentDispValue.append(sbFilename);
response.setHeader("Content-disposition", sbContentDispValue.toString());
// lookup the PO and fill in the XML with valid data
if (po != null) {
String duns = "";
if (po.getVendorDetail() != null) {
duns = StringUtils.defaultString(po.getVendorDetail().getVendorDunsNumber());
}
DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class);
String currDate = ElectronicInvoiceUtils.getDateDisplayText(dateTimeService.getCurrentDate()); // getting date in kfs format
String vendorNumber = po.getVendorDetail().getVendorNumber();
String eInvoiceFile =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"\n<!-- ******Testing tool generated XML****** Version 1.2." +
"\n\n Generated On " + currDate + " for PO " + po.getPurapDocumentIdentifier() + " (Doc# " + poDocNumber + ") -->\n\n" +
"<!-- All the cXML attributes are junk values -->\n" +
"<cXML payloadID=\"200807260401062080.964@eai002\"\n" +
" timestamp=\"2008-07-26T04:01:06-08:00\"\n" +
" version=\"1.2.014\" xml:lang=\"en\" \n" +
" xmlns=\"http://www.kuali.org/kfs/purap/electronicInvoice\" \n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
" <Header>\n" +
" <From>\n" +
" <Credential domain=\"DUNS\">\n" +
" <Identity>" + duns + "</Identity> <!-- DUNS number from PO Vendor " + vendorNumber + "-->\n" +
" </Credential>\n" +
" </From>\n" +
" <To>\n" +
" <Credential domain=\"NetworkId\">\n" +
" <Identity>" + "IU" + "</Identity> <!-- Hardcoded --> \n" +
" </Credential>\n" +
" </To>\n" +
" <Sender>\n" +
" <Credential domain=\"DUNS\">\n" +
" <Identity>" + duns + "</Identity> <!-- DUNS number from PO Vendor " + vendorNumber + "-->\n" +
" </Credential>\n" +
" <UserAgent/>\n" +
" </Sender>\n" +
" </Header>\n" +
" <Request deploymentMode=\"production\">\n" +
" <InvoiceDetailRequest>\n" +
" <InvoiceDetailRequestHeader\n" +
" invoiceDate=\"" + currDate + "\" invoiceID=\"" + RandomUtils.nextInt() + "\" operation=\"new\" purpose=\"standard\"> <!-- invoiceID=Random unique Id, invoiceDate=Curr date -->\n" +
" <InvoiceDetailHeaderIndicator/>\n" +
" <InvoiceDetailLineIndicator/>\n" +
" <InvoicePartner>\n" +
getContactXMLChunk("billTo", po) +
" </InvoicePartner>\n" +
" <InvoicePartner>\n" +
" <Contact addressID=\"" + RandomUtils.nextInt() + "\" role=\"remitTo\"> <!-- Vendor address -->\n" +
" <Name xml:lang=\"en\">\n" +
" " + po.getVendorName() + "\n" +
" </Name>\n" +
" <PostalAddress>\n" +
" <Street>" + StringUtils.defaultString(po.getVendorLine1Address()) + "</Street>\n" +
" <Street>" + StringUtils.defaultString(po.getVendorLine2Address()) + "</Street>\n" +
" <City>" + StringUtils.defaultString(po.getVendorCityName()) + "</City>\n" +
" <State>" + StringUtils.defaultString(po.getVendorStateCode()) + "</State>\n" +
" <PostalCode>" + StringUtils.defaultString(po.getVendorPostalCode()) + "</PostalCode>\n" +
" <Country isoCountryCode=\"" + StringUtils.defaultString(po.getVendorCountryCode()) + "\">\n" +
" " + StringUtils.defaultString(po.getVendorCountry().getName()) + "\n" +
" </Country>\n" +
" </PostalAddress>\n" +
" </Contact>\n" +
" </InvoicePartner>\n" +
getDeliveryAddressXMLChunk("shipTo",po) +
getPaymentTermXML(po) +
" </InvoiceDetailRequestHeader>\n" +
" <InvoiceDetailOrder>\n" +
" <InvoiceDetailOrderInfo>\n" +
" <OrderReference\n" +
" orderDate=\"" + ElectronicInvoiceUtils.getDateDisplayText(dateTimeService.getCurrentDate()) + "\" orderID=\"" + po.getPurapDocumentIdentifier() + "\"> <!--orderDate=Curr date,orderID=PO#-->\n" +
" <DocumentReference payloadID=\"NA\" /> <!--HardCoded-->\n" +
" </OrderReference>\n" +
" </InvoiceDetailOrderInfo>\n" +
" <!-- No junk values in Items-->\n";
for (int i = 0; i < po.getItems().size(); i++) {
List items = po.getItems();
PurchaseOrderItem item = (PurchaseOrderItem) items.get(i);
if (!item.getItemType().isAdditionalChargeIndicator()){
eInvoiceFile = eInvoiceFile + getPOItemXMLChunk(item);
}
}
KualiDecimal totalDollarAmt = po.getTotalDollarAmount() == null ? KualiDecimal.ZERO : po.getTotalDollarAmount();
eInvoiceFile = eInvoiceFile +
" </InvoiceDetailOrder>\n" +
" <InvoiceDetailSummary>\n" +
" <SubtotalAmount>\n" +
" <Money currency=\"USD\">" + po.getTotalPreTaxDollarAmount() + "</Money>\n" +
" </SubtotalAmount>\n" +
" <Tax>\n" +
" <Money currency=\"USD\">" + po.getTotalTaxAmount() + "</Money>\n" +
" <Description xml:lang=\"en\">Total Tax</Description>\n" +
" </Tax>\n" +
" <SpecialHandlingAmount>\n" +
" <Money currency=\"USD\">0.00</Money>\n" +
" </SpecialHandlingAmount>\n" +
" <ShippingAmount>\n" +
" <Money currency=\"USD\">0.00</Money>\n" +
" </ShippingAmount>\n" +
" <GrossAmount>\n" +
" <Money currency=\"USD\">" + totalDollarAmt + "</Money>\n" +
" </GrossAmount>\n" +
" <InvoiceDetailDiscount>\n" +
" <Money currency=\"USD\">0.00</Money>\n" +
" </InvoiceDetailDiscount>\n" +
" <NetAmount>\n" +
" <Money currency=\"USD\">" + totalDollarAmt + "</Money>\n" +
" </NetAmount>\n" +
" <DepositAmount>\n" +
" <Money currency=\"USD\">0.00</Money>\n" +
" </DepositAmount>\n" +
" <DueAmount>\n" +
" <Money currency=\"USD\">" + totalDollarAmt + "</Money>\n" +
" </DueAmount>\n" +
" </InvoiceDetailSummary>\n" +
" </InvoiceDetailRequest>\n" +
" </Request>\n" +
"</cXML>";
ServletOutputStream sos;
sos = response.getOutputStream();
ByteArrayOutputStream baOutStream = new ByteArrayOutputStream();
StringBufferInputStream inStream = new StringBufferInputStream(eInvoiceFile);
convert(baOutStream, inStream);
response.setContentLength(baOutStream.size());
baOutStream.writeTo(sos);
sos.flush();
}
return mapping.findForward(KFSConstants.MAPPING_BASIC);
}
private String getPaymentTermXML(PurchaseOrderDocument po){
String returnXML = "";
PaymentTermType paymentTerm = null;
if (po.getVendorDetail() != null){
paymentTerm = po.getVendorDetail().getVendorPaymentTerms();
}
if (paymentTerm != null){
if (paymentTerm.getVendorNetDueNumber() != null){
returnXML =
" <InvoiceDetailPaymentTerm payInNumberOfDays=\"" + paymentTerm.getVendorNetDueNumber().toString() + "\" percentageRate=\"0\" />\n";
}else if (paymentTerm.getVendorPaymentTermsPercent() != null){
returnXML =
" <InvoiceDetailPaymentTerm payInNumberOfDays=\"0\" percentageRate=\"" + paymentTerm.getVendorPaymentTermsPercent() + "\" />\n";
}
}
return returnXML;
}
private String getPOItemXMLChunk(PurchaseOrderItem item){
String itemUnitPrice = item.getItemUnitPrice() == null ?
StringUtils.EMPTY :
item.getItemUnitPrice().toString();
String subTotal = StringUtils.EMPTY;
if (item.getItemUnitPrice() != null && item.getItemQuantity() != null){
subTotal = (item.getItemUnitPrice().multiply(item.getItemQuantity().bigDecimalValue())).toString();
}
return
" <InvoiceDetailItem invoiceLineNumber=\"" + item.getItemLineNumber() + "\"\n" +
" quantity=\"" + item.getItemQuantity() + "\">\n" +
" <UnitOfMeasure>" + item.getItemUnitOfMeasureCode() + "</UnitOfMeasure>\n" +
" <UnitPrice>\n" +
" <Money currency=\"USD\">" + itemUnitPrice + "</Money>\n" +
" </UnitPrice>\n" +
" <InvoiceDetailItemReference lineNumber=\"" + item.getItemLineNumber() + "\">\n" +
" <ItemID>\n" +
" <SupplierPartID>" + StringUtils.defaultString(item.getItemCatalogNumber()) + "</SupplierPartID>\n" +
" </ItemID>\n" +
" <Description xml:lang=\"en\">" + StringUtils.defaultString(item.getItemDescription()) + "</Description>\n" +
" </InvoiceDetailItemReference>\n" +
" <SubtotalAmount>\n" +
" <Money currency=\"USD\" >" + subTotal + "</Money>\n" +
" </SubtotalAmount>\n" +
" </InvoiceDetailItem>\n";
}
private String getDeliveryAddressXMLChunk(String addressType,
PurchaseOrderDocument po){
String deliveryDate = "";
if (po.getDeliveryRequiredDate() != null){
deliveryDate = ElectronicInvoiceUtils.getDateDisplayText(po.getDeliveryRequiredDate());
}
String returnXML = "";
if (StringUtils.isNotEmpty(deliveryDate)){
returnXML += " <InvoiceDetailShipping shippingDate=\"" + deliveryDate + "\"> <!--Delivery reqd date -->\n";
}else{
returnXML += " <InvoiceDetailShipping> <!-- shipTo address same as billTo-->\n";
}
returnXML += getContactXMLChunk("shipTo",po) + " </InvoiceDetailShipping>\n";
return returnXML;
}
private String getContactXMLChunk(String addressType,
PurchaseOrderDocument po){
String returnXML =
" <Contact addressID=\"" + RandomUtils.nextInt() + "\" role=\"" + addressType + "\"> <!-- addressId=Random Unique Id -->\n" +
" <Name xml:lang=\"en\">" + po.getDeliveryCampusCode() + " - " + po.getDeliveryBuildingName() + "</Name> <!-- Format:CampusCode - Bldg Nm -->\n" +
" <PostalAddress>\n" +
" <Street>" + StringUtils.defaultString(po.getDeliveryBuildingLine1Address()) + "</Street>\n" +
" <Street>" + StringUtils.defaultString(po.getDeliveryBuildingLine2Address()) + "</Street>\n" +
" <City>" + StringUtils.defaultString(po.getDeliveryCityName()) + "</City>\n" +
" <State>" + StringUtils.defaultString(po.getDeliveryStateCode()) + "</State>\n" +
" <PostalCode>" + StringUtils.defaultString(po.getDeliveryPostalCode()) + "</PostalCode>\n" +
" <Country isoCountryCode=\"" + StringUtils.defaultString(po.getDeliveryCountryCode()) + "\">\n" +
" " + StringUtils.defaultString(po.getDeliveryCountryName()) + "\n" +
" </Country>\n" +
" </PostalAddress>\n";
if (StringUtils.isNotEmpty(po.getDeliveryToEmailAddress())){
returnXML += " <Email name=\"" + po.getDeliveryToEmailAddress() + "\">" + po.getDeliveryToEmailAddress() + "</Email>\n";
}
if (StringUtils.isNotEmpty(po.getDeliveryToPhoneNumber())){
returnXML +=
" <Phone name=\"" + po.getDeliveryToPhoneNumber() + "\">\n" +
" <TelephoneNumber>\n" +
" <CountryCode isoCountryCode=\"US\">1</CountryCode>\n" +
" <AreaOrCityCode>" + getPhoneNumber(AREA_C0DE, po.getDeliveryToPhoneNumber()) + "</AreaOrCityCode>\n" +
" <Number>" + getPhoneNumber(PHONE_NUMBER, po.getDeliveryToPhoneNumber()) + "</Number>\n" +
" </TelephoneNumber>\n" +
" </Phone>\n";
}
returnXML += " </Contact>\n";
return returnXML;
}
private String getPhoneNumber(String whichPart,String phNo){
if (StringUtils.isEmpty(phNo)){
return StringUtils.EMPTY;
}
if (StringUtils.equals(whichPart,AREA_C0DE)){
return phNo.substring(0,3);
}else if (StringUtils.equals(whichPart,PHONE_NUMBER)){
return phNo.substring(3,phNo.length());
}
return StringUtils.EMPTY;
}
private boolean convert(java.io.OutputStream out, java.io.InputStream in) {
try {
int r;
while ((r=in.read())!=-1) {
out.write(r);
}
return true;
}catch (java.io.IOException ioe) {
return false;
}
}
/**
* @return the default implementation of the KRAD DocumentService
*/
protected DocumentService getDocumentService() {
if (documentService == null) {
documentService = KRADServiceLocatorWeb.getDocumentService();
}
return documentService;
}
}