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