001/* 002 * Copyright 2006-2008 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.document.service.impl; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.ole.module.purap.PurapConstants; 020import org.kuali.ole.module.purap.businessobject.PurchaseOrderItem; 021import org.kuali.ole.module.purap.dataaccess.B2BDao; 022import org.kuali.ole.module.purap.document.PurchaseOrderDocument; 023import org.kuali.ole.module.purap.document.RequisitionDocument; 024import org.kuali.ole.module.purap.document.service.B2BPurchaseOrderService; 025import org.kuali.ole.module.purap.document.service.RequisitionService; 026import org.kuali.ole.module.purap.exception.B2BConnectionException; 027import org.kuali.ole.module.purap.exception.CxmlParseError; 028import org.kuali.ole.module.purap.util.PurApDateFormatUtils; 029import org.kuali.ole.module.purap.util.cxml.B2BParserHelper; 030import org.kuali.ole.module.purap.util.cxml.PurchaseOrderResponse; 031import org.kuali.ole.sys.context.SpringContext; 032import org.kuali.ole.vnd.businessobject.ContractManager; 033import org.kuali.rice.core.api.datetime.DateTimeService; 034import org.kuali.rice.coreservice.framework.parameter.ParameterService; 035import org.kuali.rice.kew.api.WorkflowDocument; 036import org.kuali.rice.kim.api.identity.Person; 037import org.kuali.rice.kim.api.identity.PersonService; 038import org.kuali.rice.krad.util.ObjectUtils; 039import org.springframework.transaction.annotation.Transactional; 040 041import java.text.SimpleDateFormat; 042import java.util.Date; 043import java.util.Iterator; 044import java.util.List; 045 046@Transactional 047public class B2BPurchaseOrderSciquestServiceImpl implements B2BPurchaseOrderService { 048 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(B2BPurchaseOrderSciquestServiceImpl.class); 049 050 private B2BDao b2bDao; 051 private RequisitionService requisitionService; 052 private ParameterService parameterService; 053 private PersonService personService; 054 055 // injected values 056 private String b2bEnvironment; 057 private String b2bUserAgent; 058 private String b2bPurchaseOrderURL; 059 private String b2bPurchaseOrderIdentity; 060 private String b2bPurchaseOrderPassword; 061 062 /** 063 * @see org.kuali.ole.module.purap.document.service.B2BPurchaseOrderService#sendPurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument) 064 */ 065 public String sendPurchaseOrder(PurchaseOrderDocument purchaseOrder) { 066 /* 067 * IMPORTANT DESIGN NOTE: We need the contract manager's name, phone number, and e-mail address. B2B orders that don't 068 * qualify to become APO's will have contract managers on the PO, and the ones that DO become APO's will not. We decided to 069 * always get the contract manager from the B2B contract associated with the order, and for B2B orders to ignore the 070 * contract manager field on the PO. We pull the name and phone number from the contract manager table and get the e-mail 071 * address from the user data. 072 */ 073 074 ContractManager contractManager = purchaseOrder.getVendorContract().getContractManager(); 075 String contractManagerEmail = getContractManagerEmail(contractManager); 076 077 String vendorDuns = purchaseOrder.getVendorDetail().getVendorDunsNumber(); 078 079 RequisitionDocument r = requisitionService.getRequisitionById(purchaseOrder.getRequisitionIdentifier()); 080 WorkflowDocument reqWorkflowDoc = r.getDocumentHeader().getWorkflowDocument(); 081 082 if (LOG.isDebugEnabled()) { 083 LOG.debug("sendPurchaseOrder(): b2bPurchaseOrderURL is " + b2bPurchaseOrderURL); 084 } 085 086 String validateErrors = verifyCxmlPOData(purchaseOrder, reqWorkflowDoc.getInitiatorPrincipalId(), b2bPurchaseOrderPassword, contractManager, contractManagerEmail, vendorDuns); 087 if (!StringUtils.isEmpty(validateErrors)) { 088 return validateErrors; 089 } 090 091 StringBuffer transmitErrors = new StringBuffer(); 092 093 try { 094 LOG.debug("sendPurchaseOrder() Generating cxml"); 095 String cxml = getCxml(purchaseOrder, reqWorkflowDoc.getInitiatorPrincipalId(), b2bPurchaseOrderPassword, contractManager, contractManagerEmail, vendorDuns); 096 097 LOG.info("sendPurchaseOrder() Sending cxml\n" + cxml); 098 String responseCxml = b2bDao.sendPunchOutRequest(cxml, b2bPurchaseOrderURL); 099 100 LOG.info("sendPurchaseOrder(): Response cXML for po #" + purchaseOrder.getPurapDocumentIdentifier() + ":\n" + responseCxml); 101 102 PurchaseOrderResponse poResponse = B2BParserHelper.getInstance().parsePurchaseOrderResponse(responseCxml); 103 String statusText = poResponse.getStatusText(); 104 if (LOG.isDebugEnabled()) { 105 LOG.debug("sendPurchaseOrder(): statusText is " + statusText); 106 } 107 if (ObjectUtils.isNull(statusText) || (!"success".equalsIgnoreCase(statusText.trim()))) { 108 LOG.error("sendPurchaseOrder(): PO cXML for po number " + purchaseOrder.getPurapDocumentIdentifier() + " failed sending to SciQuest:\n" + statusText); 109 transmitErrors.append("Unable to send Purchase Order: " + statusText); 110 111 // find any additional error messages that might have been sent 112 List errorMessages = poResponse.getPOResponseErrorMessages(); 113 if (ObjectUtils.isNotNull(errorMessages) && !errorMessages.isEmpty()) { 114 for (Iterator iter = errorMessages.iterator(); iter.hasNext(); ) { 115 String errorMessage = (String) iter.next(); 116 if (ObjectUtils.isNotNull(errorMessage)) { 117 LOG.error("sendPurchaseOrder(): SciQuest error message for po number " + purchaseOrder.getPurapDocumentIdentifier() + ": " + errorMessage); 118 transmitErrors.append("Error sending Purchase Order: " + errorMessage); 119 } 120 } 121 } 122 } 123 } catch (B2BConnectionException e) { 124 LOG.error("sendPurchaseOrder() Error connecting to b2b", e); 125 transmitErrors.append("Connection to Sciquest failed."); 126 } catch (CxmlParseError e) { 127 LOG.error("sendPurchaseOrder() Error Parsing", e); 128 transmitErrors.append("Unable to read cxml returned from Sciquest."); 129 } catch (Throwable e) { 130 LOG.error("sendPurchaseOrder() Unknown Error", e); 131 transmitErrors.append("Unexpected error occurred while attempting to transmit Purchase Order."); 132 } 133 134 return transmitErrors.toString(); 135 } 136 137 /** 138 * @see org.kuali.ole.module.purap.document.service.B2BPurchaseOrderService#getCxml(org.kuali.ole.module.purap.document.PurchaseOrderDocument, 139 * org.kuali.rice.kim.api.identity.Person, java.lang.String, org.kuali.ole.vnd.businessobject.ContractManager, 140 * java.lang.String, java.lang.String) 141 */ 142 public String getCxml(PurchaseOrderDocument purchaseOrder, String requisitionInitiatorId, String password, ContractManager contractManager, String contractManagerEmail, String vendorDuns) { 143 144 StringBuffer cxml = new StringBuffer(); 145 146 cxml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 147 cxml.append("<!DOCTYPE PurchaseOrderMessage SYSTEM \"PO.dtd\">\n"); 148 cxml.append("<PurchaseOrderMessage version=\"2.0\">\n"); 149 cxml.append(" <Header>\n"); 150 151 // MessageId - can be whatever you would like it to be. Just make it unique. 152 cxml.append(" <MessageId>KFS_cXML_PO</MessageId>\n"); 153 154 // Timestamp - it doesn't matter what's in the timezone, just that it's there (need "T" space between date/time) 155 Date d = SpringContext.getBean(DateTimeService.class).getCurrentDate(); 156 SimpleDateFormat date = PurApDateFormatUtils.getSimpleDateFormat(PurapConstants.NamedDateFormats.CXML_SIMPLE_DATE_FORMAT); 157 SimpleDateFormat time = PurApDateFormatUtils.getSimpleDateFormat(PurapConstants.NamedDateFormats.CXML_SIMPLE_TIME_FORMAT); 158 cxml.append(" <Timestamp>").append(date.format(d)).append("T").append(time.format(d)).append("+05:30").append("</Timestamp>\n"); 159 160 cxml.append(" <Authentication>\n"); 161 cxml.append(" <Identity>").append(b2bPurchaseOrderIdentity).append("</Identity>\n"); 162 cxml.append(" <SharedSecret>").append(password).append("</SharedSecret>\n"); 163 cxml.append(" </Authentication>\n"); 164 cxml.append(" </Header>\n"); 165 cxml.append(" <PurchaseOrder>\n"); 166 cxml.append(" <POHeader>\n"); 167 cxml.append(" <PONumber>").append(purchaseOrder.getPurapDocumentIdentifier()).append("</PONumber>\n"); 168 cxml.append(" <Requestor>\n"); 169 cxml.append(" <UserProfile username=\"").append(requisitionInitiatorId.toUpperCase()).append("\">\n"); 170 cxml.append(" </UserProfile>\n"); 171 cxml.append(" </Requestor>\n"); 172 cxml.append(" <Priority>High</Priority>\n"); 173 cxml.append(" <AccountingDate>").append(purchaseOrder.getPurchaseOrderCreateTimestamp()).append("</AccountingDate>\n"); 174 175 /** *** SUPPLIER SECTION **** */ 176 cxml.append(" <Supplier id=\"").append(purchaseOrder.getExternalOrganizationB2bSupplierIdentifier()).append("\">\n"); 177 cxml.append(" <DUNS>").append(vendorDuns).append("</DUNS>\n"); 178 cxml.append(" <SupplierNumber>").append(purchaseOrder.getVendorNumber()).append("</SupplierNumber>\n"); 179 180 // Type attribute is required. Valid values: main and technical. Only main will be considered for POImport. 181 cxml.append(" <ContactInfo type=\"main\">\n"); 182 // TelephoneNumber is required. With all fields, only numeric digits will be stored. Non-numeric characters are allowed, but 183 // will be stripped before storing. 184 cxml.append(" <Phone>\n"); 185 cxml.append(" <TelephoneNumber>\n"); 186 cxml.append(" <CountryCode>1</CountryCode>\n"); 187 if (contractManager.getContractManagerPhoneNumber().length() > 4) { 188 cxml.append(" <AreaCode>").append(contractManager.getContractManagerPhoneNumber().substring(0, 3)).append("</AreaCode>\n"); 189 cxml.append(" <Number>").append(contractManager.getContractManagerPhoneNumber().substring(3)).append("</Number>\n"); 190 } else { 191 LOG.error("getCxml() The phone number is invalid for this contract manager: " + contractManager.getContractManagerUserIdentifier() + " " + contractManager.getContractManagerName()); 192 cxml.append(" <AreaCode>555</AreaCode>\n"); 193 cxml.append(" <Number>").append(contractManager.getContractManagerPhoneNumber()).append("</Number>\n"); 194 } 195 cxml.append(" </TelephoneNumber>\n"); 196 cxml.append(" </Phone>\n"); 197 cxml.append(" </ContactInfo>\n"); 198 cxml.append(" </Supplier>\n"); 199 200 /** *** BILL TO SECTION **** */ 201 cxml.append(" <BillTo>\n"); 202 cxml.append(" <Address>\n"); 203 cxml.append(" <TemplateName>Bill To</TemplateName>\n"); 204 cxml.append(" <AddressCode>").append(purchaseOrder.getDeliveryCampusCode()).append("</AddressCode>\n"); 205 // Contact - There can be 0-5 Contact elements. The label attribute is optional. 206 cxml.append(" <Contact label=\"FirstName\" linenumber=\"1\"><![CDATA[Accounts]]></Contact>\n"); 207 cxml.append(" <Contact label=\"LastName\" linenumber=\"2\"><![CDATA[Payable]]></Contact>\n"); 208 cxml.append(" <Contact label=\"Company\" linenumber=\"3\"><![CDATA[").append(purchaseOrder.getBillingName().trim()).append("]]></Contact>\n"); 209 // since email address is not required, we need to check whether its empty; if yes, don't add it 210 if (!StringUtils.isEmpty(purchaseOrder.getBillingEmailAddress())) { 211 cxml.append(" <Contact label=\"Email\" linenumber=\"4\"><![CDATA[").append(purchaseOrder.getBillingEmailAddress().trim()).append("]]></Contact>\n"); 212 } 213 // since phone number is not required, we need to check whether its empty; if yes, don't add it 214 if (!StringUtils.isEmpty(purchaseOrder.getBillingPhoneNumber())) { 215 cxml.append(" <Contact label=\"Phone\" linenumber=\"5\"><![CDATA[").append(purchaseOrder.getBillingPhoneNumber().trim()).append("]]></Contact>\n"); 216 } 217 // There must be 1-5 AddressLine elements. The label attribute is optional. 218 cxml.append(" <AddressLine label=\"Street1\" linenumber=\"1\"><![CDATA[").append(purchaseOrder.getBillingLine1Address()).append("]]></AddressLine>\n"); 219 cxml.append(" <AddressLine label=\"Street2\" linenumber=\"2\"><![CDATA[").append(purchaseOrder.getBillingLine2Address()).append("]]></AddressLine>\n"); 220 cxml.append(" <City><![CDATA[").append(purchaseOrder.getBillingCityName()).append("]]></City>\n"); // Required. 221 cxml.append(" <State>").append(purchaseOrder.getBillingStateCode()).append("</State>\n"); 222 cxml.append(" <PostalCode>").append(purchaseOrder.getBillingPostalCode()).append("</PostalCode>\n"); // Required. 223 cxml.append(" <Country isocountrycode=\"").append(purchaseOrder.getBillingCountryCode()).append("\">").append(purchaseOrder.getBillingCountryCode()).append("</Country>\n"); 224 cxml.append(" </Address>\n"); 225 cxml.append(" </BillTo>\n"); 226 227 /** *** SHIP TO SECTION **** */ 228 cxml.append(" <ShipTo>\n"); 229 cxml.append(" <Address>\n"); 230 cxml.append(" <TemplateName>Ship To</TemplateName>\n"); 231 // AddressCode. A code to identify the address, that is sent to the supplier. 232 cxml.append(" <AddressCode>").append(purchaseOrder.getDeliveryCampusCode()).append(purchaseOrder.getOrganizationCode()).append("</AddressCode>\n"); 233 cxml.append(" <Contact label=\"Name\" linenumber=\"1\"><![CDATA[").append(purchaseOrder.getDeliveryToName().trim()).append("]]></Contact>\n"); 234 cxml.append(" <Contact label=\"PurchasingEmail\" linenumber=\"2\"><![CDATA[").append(contractManagerEmail).append("]]></Contact>\n"); 235 if (ObjectUtils.isNotNull(purchaseOrder.getInstitutionContactEmailAddress())) { 236 cxml.append(" <Contact label=\"ContactEmail\" linenumber=\"3\"><![CDATA[").append(purchaseOrder.getInstitutionContactEmailAddress()).append("]]></Contact>\n"); 237 } else { 238 cxml.append(" <Contact label=\"ContactEmail\" linenumber=\"3\"><![CDATA[").append(purchaseOrder.getRequestorPersonEmailAddress()).append("]]></Contact>\n"); 239 } 240 if (ObjectUtils.isNotNull(purchaseOrder.getInstitutionContactPhoneNumber())) { 241 cxml.append(" <Contact label=\"Phone\" linenumber=\"4\"><![CDATA[").append(purchaseOrder.getInstitutionContactPhoneNumber().trim()).append("]]></Contact>\n"); 242 } else { 243 cxml.append(" <Contact label=\"Phone\" linenumber=\"4\"><![CDATA[").append(purchaseOrder.getRequestorPersonPhoneNumber()).append("]]></Contact>\n"); 244 } 245 246 //check indicator to decide if receiving or delivery address should be sent to the vendor 247 if (purchaseOrder.getAddressToVendorIndicator()) { //use receiving address 248 cxml.append(" <AddressLine label=\"Street1\" linenumber=\"1\"><![CDATA[").append(purchaseOrder.getReceivingName().trim()).append("]]></AddressLine>\n"); 249 cxml.append(" <AddressLine label=\"Street2\" linenumber=\"2\"><![CDATA[").append(purchaseOrder.getReceivingLine1Address().trim()).append("]]></AddressLine>\n"); 250 if (ObjectUtils.isNull(purchaseOrder.getReceivingLine2Address())) { 251 cxml.append(" <AddressLine label=\"Street3\" linenumber=\"3\"><![CDATA[").append(" ").append("]]></AddressLine>\n"); 252 } else { 253 cxml.append(" <AddressLine label=\"Street3\" linenumber=\"3\"><![CDATA[").append(purchaseOrder.getReceivingLine2Address()).append("]]></AddressLine>\n"); 254 } 255 cxml.append(" <City><![CDATA[").append(purchaseOrder.getReceivingCityName().trim()).append("]]></City>\n"); 256 cxml.append(" <State>").append(purchaseOrder.getReceivingStateCode()).append("</State>\n"); 257 cxml.append(" <PostalCode>").append(purchaseOrder.getReceivingPostalCode()).append("</PostalCode>\n"); 258 cxml.append(" <Country isocountrycode=\"").append(purchaseOrder.getReceivingCountryCode()).append("\">").append(purchaseOrder.getReceivingCountryCode()).append("</Country>\n"); 259 } else { //use final delivery address 260 if (StringUtils.isNotEmpty(purchaseOrder.getDeliveryBuildingName())) { 261 cxml.append(" <Contact label=\"Building\" linenumber=\"5\"><![CDATA[").append(purchaseOrder.getDeliveryBuildingName()).append(" (").append(purchaseOrder.getDeliveryBuildingCode()).append(")]]></Contact>\n"); 262 } 263 cxml.append(" <AddressLine label=\"Street1\" linenumber=\"1\"><![CDATA[").append(purchaseOrder.getDeliveryBuildingLine1Address().trim()).append("]]></AddressLine>\n"); 264 cxml.append(" <AddressLine label=\"Street2\" linenumber=\"2\"><![CDATA[Room #").append(purchaseOrder.getDeliveryBuildingRoomNumber().trim()).append("]]></AddressLine>\n"); 265 cxml.append(" <AddressLine label=\"Company\" linenumber=\"4\"><![CDATA[").append(purchaseOrder.getBillingName().trim()).append("]]></AddressLine>\n"); 266 if (ObjectUtils.isNull(purchaseOrder.getDeliveryBuildingLine2Address())) { 267 cxml.append(" <AddressLine label=\"Street3\" linenumber=\"3\"><![CDATA[").append(" ").append("]]></AddressLine>\n"); 268 } else { 269 cxml.append(" <AddressLine label=\"Street3\" linenumber=\"3\"><![CDATA[").append(purchaseOrder.getDeliveryBuildingLine2Address()).append("]]></AddressLine>\n"); 270 } 271 cxml.append(" <City><![CDATA[").append(purchaseOrder.getDeliveryCityName().trim()).append("]]></City>\n"); 272 cxml.append(" <State>").append(purchaseOrder.getDeliveryStateCode()).append("</State>\n"); 273 cxml.append(" <PostalCode>").append(purchaseOrder.getDeliveryPostalCode()).append("</PostalCode>\n"); 274 cxml.append(" <Country isocountrycode=\"").append(purchaseOrder.getDeliveryCountryCode()).append("\">").append(purchaseOrder.getDeliveryCountryCode()).append("</Country>\n"); 275 } 276 277 cxml.append(" </Address>\n"); 278 cxml.append(" </ShipTo>\n"); 279 cxml.append(" </POHeader>\n"); 280 281 /** *** Items Section **** */ 282 List detailList = purchaseOrder.getItems(); 283 for (Iterator iter = detailList.iterator(); iter.hasNext(); ) { 284 PurchaseOrderItem poi = (PurchaseOrderItem) iter.next(); 285 if ((ObjectUtils.isNotNull(poi.getItemType())) && poi.getItemType().isLineItemIndicator()) { 286 cxml.append(" <POLine linenumber=\"").append(poi.getItemLineNumber()).append("\">\n"); 287 cxml.append(" <Item>\n"); 288 // CatalogNumber - This is a string that the supplier uses to identify the item (i.e., SKU). Optional. 289 cxml.append(" <CatalogNumber><![CDATA[").append(poi.getItemCatalogNumber()).append("]]></CatalogNumber>\n"); 290 if (ObjectUtils.isNotNull(poi.getItemAuxiliaryPartIdentifier())) { 291 cxml.append(" <AuxiliaryCatalogNumber><![CDATA[").append(poi.getItemAuxiliaryPartIdentifier()).append("]]></AuxiliaryCatalogNumber>\n"); 292 } 293 cxml.append(" <Description><![CDATA[").append(poi.getItemDescription()).append("]]></Description>\n"); // Required. 294 cxml.append(" <ProductUnitOfMeasure type=\"supplier\"><Measurement><MeasurementValue><![CDATA[").append(poi.getItemUnitOfMeasureCode()).append("]]></MeasurementValue></Measurement></ProductUnitOfMeasure>\n"); 295 cxml.append(" <ProductUnitOfMeasure type=\"system\"><Measurement><MeasurementValue><![CDATA[").append(poi.getItemUnitOfMeasureCode()).append("]]></MeasurementValue></Measurement></ProductUnitOfMeasure>\n"); 296 // ProductReferenceNumber - Unique id for hosted products in SelectSite 297 if (poi.getExternalOrganizationB2bProductTypeName().equals("Punchout")) { 298 cxml.append(" <ProductReferenceNumber>null</ProductReferenceNumber>\n"); 299 } else { 300 cxml.append(" <ProductReferenceNumber>").append(poi.getExternalOrganizationB2bProductReferenceNumber()).append("</ProductReferenceNumber>\n"); 301 } 302 // ProductType - Describes the type of the product or service. Valid values: Catalog, Form, Punchout. Mandatory. 303 cxml.append(" <ProductType>").append(poi.getExternalOrganizationB2bProductTypeName()).append("</ProductType>\n"); 304 cxml.append(" </Item>\n"); 305 cxml.append(" <Quantity>").append(poi.getItemQuantity()).append("</Quantity>\n"); 306 // LineCharges - All the monetary charges for this line, including the price, tax, shipping, and handling. 307 // Required. 308 cxml.append(" <LineCharges>\n"); 309 cxml.append(" <UnitPrice>\n"); 310 cxml.append(" <Money currency=\"USD\">").append(poi.getItemUnitPrice()).append("</Money>\n"); 311 cxml.append(" </UnitPrice>\n"); 312 cxml.append(" </LineCharges>\n"); 313 cxml.append(" </POLine>\n"); 314 } 315 } 316 317 cxml.append(" </PurchaseOrder>\n"); 318 cxml.append("</PurchaseOrderMessage>"); 319 320 if (LOG.isDebugEnabled()) { 321 LOG.debug("getCxml(): cXML for po number " + purchaseOrder.getPurapDocumentIdentifier() + ":\n" + cxml.toString()); 322 } 323 324 return cxml.toString(); 325 } 326 327 /** 328 * @see org.kuali.ole.module.purap.document.service.B2BPurchaseOrderService#verifyCxmlPOData(org.kuali.ole.module.purap.document.PurchaseOrderDocument, 329 * org.kuali.rice.kim.api.identity.Person, java.lang.String, org.kuali.ole.vnd.businessobject.ContractManager, 330 * java.lang.String, java.lang.String) 331 */ 332 public String verifyCxmlPOData(PurchaseOrderDocument purchaseOrder, String requisitionInitiatorId, String password, ContractManager contractManager, String contractManagerEmail, String vendorDuns) { 333 StringBuffer errors = new StringBuffer(); 334 335 if (ObjectUtils.isNull(purchaseOrder)) { 336 LOG.error("verifyCxmlPOData() The Purchase Order is null."); 337 errors.append("Error occurred retrieving Purchase Order\n"); 338 return errors.toString(); 339 } 340 if (ObjectUtils.isNull(contractManager)) { 341 LOG.error("verifyCxmlPOData() The contractManager is null."); 342 errors.append("Error occurred retrieving Contract Manager\n"); 343 return errors.toString(); 344 } 345 if (StringUtils.isEmpty(password)) { 346 LOG.error("verifyCxmlPOData() The B2B PO password is required for the cXML PO but is missing."); 347 errors.append("Missing Data: B2B PO password\n"); 348 } 349 if (ObjectUtils.isNull(purchaseOrder.getPurapDocumentIdentifier())) { 350 LOG.error("verifyCxmlPOData() The purchase order Id is required for the cXML PO but is missing."); 351 errors.append("Missing Data: Purchase Order ID\n"); 352 } 353 if (StringUtils.isEmpty(requisitionInitiatorId)) { 354 LOG.error("verifyCxmlPOData() The requisition initiator Network Id is required for the cXML PO but is missing."); 355 errors.append("Missing Data: Requisition Initiator NetworkId\n"); 356 } 357 if (ObjectUtils.isNull(purchaseOrder.getPurchaseOrderCreateTimestamp())) { 358 LOG.error("verifyCxmlPOData() The PO create date is required for the cXML PO but is null."); 359 errors.append("Create Date\n"); 360 } 361 if (StringUtils.isEmpty(contractManager.getContractManagerPhoneNumber())) { 362 LOG.error("verifyCxmlPOData() The contract manager phone number is required for the cXML PO but is missing."); 363 errors.append("Missing Data: Contract Manager Phone Number\n"); 364 } 365 if (StringUtils.isEmpty(contractManager.getContractManagerName())) { 366 LOG.error("verifyCxmlPOData() The contract manager name is required for the cXML PO but is missing."); 367 errors.append("Missing Data: Contract Manager Name\n"); 368 } 369 if (StringUtils.isEmpty(purchaseOrder.getDeliveryCampusCode())) { 370 LOG.error("verifyCxmlPOData() The Delivery Campus Code is required for the cXML PO but is missing."); 371 errors.append("Missing Data: Delivery Campus Code\n"); 372 } 373 if (StringUtils.isEmpty(purchaseOrder.getBillingName())) { 374 LOG.error("verifyCxmlPOData() The Delivery Billing Name is required for the cXML PO but is missing."); 375 errors.append("Missing Data: Delivery Billing Name\n"); 376 } 377 if (StringUtils.isEmpty(purchaseOrder.getBillingLine1Address())) { 378 LOG.error("verifyCxmlPOData() The Billing Line 1 Address is required for the cXML PO but is missing."); 379 errors.append("Missing Data: Billing Line 1 Address\n"); 380 } 381 if (StringUtils.isEmpty(purchaseOrder.getBillingLine2Address())) { 382 LOG.error("verifyCxmlPOData() The Billing Line 2 Address is required for the cXML PO but is missing."); 383 errors.append("Missing Data: Billing Line 2 Address\n"); 384 } 385 if (StringUtils.isEmpty(purchaseOrder.getBillingCityName())) { 386 LOG.error("verifyCxmlPOData() The Billing Address City Name is required for the cXML PO but is missing."); 387 errors.append("Missing Data: Billing Address City Name\n"); 388 } 389 if (StringUtils.isEmpty(purchaseOrder.getBillingStateCode())) { 390 LOG.error("verifyCxmlPOData() The Billing Address State Code is required for the cXML PO but is missing."); 391 errors.append("Missing Data: Billing Address State Code\n"); 392 } 393 if (StringUtils.isEmpty(purchaseOrder.getBillingPostalCode())) { 394 LOG.error("verifyCxmlPOData() The Billing Address Postal Code is required for the cXML PO but is missing."); 395 errors.append("Missing Data: Billing Address Postal Code\n"); 396 } 397 if (StringUtils.isEmpty(purchaseOrder.getDeliveryToName())) { 398 LOG.error("verifyCxmlPOData() The Delivery To Name is required for the cXML PO but is missing."); 399 errors.append("Missing Data: Delivery To Name\n"); 400 } 401 if (StringUtils.isEmpty(contractManagerEmail)) { 402 LOG.error("verifyCxmlPOData() The Contract Manager Email is required for the cXML PO but is missing."); 403 errors.append("Missing Data: Contract Manager Email\n"); 404 } 405 if (StringUtils.isEmpty(purchaseOrder.getRequestorPersonEmailAddress())) { 406 LOG.error("verifyCxmlPOData() The Requesting Person Email Address is required for the cXML PO but is missing."); 407 errors.append("Missing Data: Requesting Person Email Address\n"); 408 } 409 if (StringUtils.isEmpty(purchaseOrder.getRequestorPersonPhoneNumber())) { 410 LOG.error("verifyCxmlPOData() The Requesting Person Phone Number is required for the cXML PO but is missing."); 411 errors.append("Missing Data: Requesting Person Phone Number\n"); 412 } 413 if (StringUtils.isEmpty(purchaseOrder.getDeliveryBuildingLine1Address())) { 414 LOG.error("verifyCxmlPOData() The Delivery Line 1 Address is required for the cXML PO but is missing."); 415 errors.append("Missing Data: Delivery Line 1 Address\n"); 416 } 417 if (StringUtils.isEmpty(purchaseOrder.getDeliveryToName())) { 418 LOG.error("verifyCxmlPOData() The Delivery To Name is required for the cXML PO but is missing."); 419 errors.append("Missing Data: Delivery To Name\n"); 420 } 421 if (StringUtils.isEmpty(purchaseOrder.getDeliveryCityName())) { 422 LOG.error("verifyCxmlPOData() The Delivery City Name is required for the cXML PO but is missing."); 423 errors.append("Missing Data: Delivery City Name\n"); 424 } 425 if (StringUtils.isEmpty(purchaseOrder.getDeliveryStateCode())) { 426 LOG.error("verifyCxmlPOData() The Delivery State is required for the cXML PO but is missing."); 427 errors.append("Missing Data: Delivery State\n"); 428 } 429 if (StringUtils.isEmpty(purchaseOrder.getDeliveryPostalCode())) { 430 LOG.error("verifyCxmlPOData() The Delivery Postal Code is required for the cXML PO but is missing."); 431 errors.append("Missing Data: Delivery Postal Code\n"); 432 } 433 434 // verify item data 435 List detailList = purchaseOrder.getItems(); 436 for (Iterator iter = detailList.iterator(); iter.hasNext(); ) { 437 PurchaseOrderItem poi = (PurchaseOrderItem) iter.next(); 438 if (ObjectUtils.isNotNull(poi.getItemType()) && poi.getItemType().isLineItemIndicator()) { 439 if (ObjectUtils.isNull(poi.getItemLineNumber())) { 440 LOG.error("verifyCxmlPOData() The Item Line Number is required for the cXML PO but is missing."); 441 errors.append("Missing Data: Item Line Number\n"); 442 } 443 if (StringUtils.isEmpty(poi.getItemCatalogNumber())) { 444 LOG.error("verifyCxmlPOData() The Catalog Number for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing."); 445 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Catalog Number\n"); 446 } 447 if (StringUtils.isEmpty(poi.getItemDescription())) { 448 LOG.error("verifyCxmlPOData() The Description for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing."); 449 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Description\n"); 450 } 451 if (StringUtils.isEmpty(poi.getItemUnitOfMeasureCode())) { 452 LOG.error("verifyCxmlPOData() The Unit Of Measure Code for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing."); 453 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Unit Of Measure\n"); 454 } 455 if (StringUtils.isEmpty(poi.getExternalOrganizationB2bProductTypeName())) { 456 LOG.error("verifyCxmlPOData() The External Org B2B Product Type Name for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing."); 457 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - External Org B2B Product Type Name\n"); 458 } 459 if (poi.getItemQuantity() == null) { 460 LOG.error("verifyCxmlPOData() The Order Quantity for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing."); 461 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Order Quantity\n"); 462 } 463 if (poi.getItemUnitPrice() == null) { 464 LOG.error("verifyCxmlPOData() The Unit Price for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing."); 465 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Unit Price\n"); 466 } 467 } 468 } // end item looping 469 470 return errors.toString(); 471 } 472 473 /** 474 * Retrieve the Contract Manager's email 475 */ 476 protected String getContractManagerEmail(ContractManager cm) { 477 478 Person contractManager = getPersonService().getPerson(cm.getContractManagerUserIdentifier()); 479 if (ObjectUtils.isNotNull(contractManager)) { 480 return contractManager.getEmailAddressUnmasked(); 481 } 482 return ""; 483 } 484 485 public void setRequisitionService(RequisitionService requisitionService) { 486 this.requisitionService = requisitionService; 487 } 488 489 public void setParameterService(ParameterService parameterService) { 490 this.parameterService = parameterService; 491 } 492 493 public void setB2bDao(B2BDao b2bDao) { 494 this.b2bDao = b2bDao; 495 } 496 497 /** 498 * @return Returns the personService. 499 */ 500 protected PersonService getPersonService() { 501 if (personService == null) 502 personService = SpringContext.getBean(PersonService.class); 503 return personService; 504 } 505 506 public void setB2bEnvironment(String environment) { 507 b2bEnvironment = environment; 508 } 509 510 public void setB2bUserAgent(String userAgent) { 511 b2bUserAgent = userAgent; 512 } 513 514 public void setB2bPurchaseOrderURL(String purchaseOrderURL) { 515 b2bPurchaseOrderURL = purchaseOrderURL; 516 } 517 518 public void setB2bPurchaseOrderIdentity(String b2bPurchaseOrderIdentity) { 519 this.b2bPurchaseOrderIdentity = b2bPurchaseOrderIdentity; 520 } 521 522 public void setB2bPurchaseOrderPassword(String purchaseOrderPassword) { 523 b2bPurchaseOrderPassword = purchaseOrderPassword; 524 } 525 526}