View Javadoc
1   /*
2    * Copyright 2006-2008 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.module.purap.document.service.impl;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.ole.module.purap.PurapConstants;
20  import org.kuali.ole.module.purap.businessobject.PurchaseOrderItem;
21  import org.kuali.ole.module.purap.dataaccess.B2BDao;
22  import org.kuali.ole.module.purap.document.PurchaseOrderDocument;
23  import org.kuali.ole.module.purap.document.RequisitionDocument;
24  import org.kuali.ole.module.purap.document.service.B2BPurchaseOrderService;
25  import org.kuali.ole.module.purap.document.service.RequisitionService;
26  import org.kuali.ole.module.purap.exception.B2BConnectionException;
27  import org.kuali.ole.module.purap.exception.CxmlParseError;
28  import org.kuali.ole.module.purap.util.PurApDateFormatUtils;
29  import org.kuali.ole.module.purap.util.cxml.B2BParserHelper;
30  import org.kuali.ole.module.purap.util.cxml.PurchaseOrderResponse;
31  import org.kuali.ole.sys.OLEConstants;
32  import org.kuali.ole.sys.context.SpringContext;
33  import org.kuali.ole.vnd.businessobject.ContractManager;
34  import org.kuali.rice.core.api.config.property.ConfigurationService;
35  import org.kuali.rice.core.api.datetime.DateTimeService;
36  import org.kuali.rice.coreservice.framework.parameter.ParameterService;
37  import org.kuali.rice.kew.api.WorkflowDocument;
38  import org.kuali.rice.kim.api.identity.Person;
39  import org.kuali.rice.kim.api.identity.PersonService;
40  import org.kuali.rice.krad.util.ObjectUtils;
41  import org.springframework.transaction.annotation.Transactional;
42  
43  import java.text.SimpleDateFormat;
44  import java.util.Date;
45  import java.util.Iterator;
46  import java.util.List;
47  
48  @Transactional
49  public class B2BPurchaseOrderServiceImpl implements B2BPurchaseOrderService {
50      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(B2BPurchaseOrderServiceImpl.class);
51  
52      private B2BDao b2bDao;
53      private RequisitionService requisitionService;
54      private ParameterService parameterService;
55      private PersonService personService;
56  
57      // injected values
58      private String b2bEnvironment;
59      private String b2bUserAgent;
60      private String b2bPurchaseOrderURL;
61      private String b2bPurchaseOrderIdentity;
62      private String b2bPurchaseOrderPassword;
63  
64      /**
65       * @see org.kuali.ole.module.purap.document.service.B2BPurchaseOrderService#sendPurchaseOrder(org.kuali.ole.module.purap.document.PurchaseOrderDocument)
66       */
67      public String sendPurchaseOrder(PurchaseOrderDocument purchaseOrder) {
68          /*
69           * IMPORTANT DESIGN NOTE: We need the contract manager's name, phone number, and e-mail address. B2B orders that don't
70           * 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
71           * always get the contract manager from the B2B contract associated with the order, and for B2B orders to ignore the
72           * contract manager field on the PO. We pull the name and phone number from the contract manager table and get the e-mail
73           * address from the user data.
74           */
75  
76          ContractManager contractManager = purchaseOrder.getVendorContract().getContractManager();
77          String contractManagerEmail = getContractManagerEmail(contractManager);
78  
79          String vendorDuns = purchaseOrder.getVendorDetail().getVendorDunsNumber();
80  
81          RequisitionDocument r = requisitionService.getRequisitionById(purchaseOrder.getRequisitionIdentifier());
82          WorkflowDocument reqWorkflowDoc = r.getDocumentHeader().getWorkflowDocument();
83  
84          if (LOG.isDebugEnabled()) {
85              LOG.debug("sendPurchaseOrder(): b2bPurchaseOrderURL is " + b2bPurchaseOrderURL);
86          }
87  
88          String validateErrors = verifyCxmlPOData(purchaseOrder, reqWorkflowDoc.getInitiatorPrincipalId(), b2bPurchaseOrderPassword, contractManager, contractManagerEmail, vendorDuns);
89          if (StringUtils.isEmpty(validateErrors)) {
90              return validateErrors;
91          }
92  
93          StringBuffer transmitErrors = new StringBuffer();
94  
95          try {
96              LOG.debug("sendPurchaseOrder() Generating cxml");
97              String cxml = getCxml(purchaseOrder, reqWorkflowDoc.getInitiatorPrincipalId(), b2bPurchaseOrderPassword, contractManager, contractManagerEmail, vendorDuns);
98  
99              LOG.info("sendPurchaseOrder() Sending cxml\n" + cxml);
100             String responseCxml = b2bDao.sendPunchOutRequest(cxml, b2bPurchaseOrderURL);
101 
102             LOG.info("sendPurchaseOrder(): Response cXML for po #" + purchaseOrder.getPurapDocumentIdentifier() + ":\n" + responseCxml);
103 
104             PurchaseOrderResponse poResponse = B2BParserHelper.getInstance().parsePurchaseOrderResponse(responseCxml);
105             String statusText = poResponse.getStatusText();
106             if (LOG.isDebugEnabled()) {
107                 LOG.debug("sendPurchaseOrder(): statusText is " + statusText);
108             }
109             if ((ObjectUtils.isNull(statusText)) || (!"success".equalsIgnoreCase(statusText.trim()))) {
110                 LOG.error("sendPurchaseOrder(): PO cXML for po number " + purchaseOrder.getPurapDocumentIdentifier() + " failed sending to vendor: " + statusText);
111                 transmitErrors.append("Unable to send Purchase Order: " + statusText);
112 
113                 // find any additional error messages that might have been sent
114                 List errorMessages = poResponse.getPOResponseErrorMessages();
115                 if (ObjectUtils.isNotNull(errorMessages) && !errorMessages.isEmpty()) {
116                     for (Iterator iter = errorMessages.iterator(); iter.hasNext(); ) {
117                         String errorMessage = (String) iter.next();
118                         if (ObjectUtils.isNotNull(errorMessage)) {
119                             LOG.error("sendPurchaseOrder(): Error message for po number " + purchaseOrder.getPurapDocumentIdentifier() + ": " + errorMessage);
120                             transmitErrors.append("Error sending Purchase Order: " + errorMessage);
121                         }
122                     }
123                 }
124             }
125         } catch (B2BConnectionException e) {
126             LOG.error("sendPurchaseOrder() Error connecting to b2b", e);
127             transmitErrors.append("Connection to vendor failed.");
128         } catch (CxmlParseError e) {
129             LOG.error("sendPurchaseOrder() Error Parsing", e);
130             transmitErrors.append("Unable to read cxml returned from vendor.");
131         } catch (Throwable e) {
132             LOG.error("sendPurchaseOrder() Unknown Error", e);
133             transmitErrors.append("Unexpected error occurred while attempting to transmit Purchase Order.");
134         }
135 
136         return transmitErrors.toString();
137     }
138 
139     /**
140      * @see org.kuali.ole.module.purap.document.service.B2BPurchaseOrderService#getCxml(org.kuali.ole.module.purap.document.PurchaseOrderDocument,
141      *      org.kuali.rice.kim.api.identity.Person, java.lang.String, org.kuali.ole.vnd.businessobject.ContractManager,
142      *      java.lang.String, java.lang.String)
143      */
144     public String getCxml(PurchaseOrderDocument purchaseOrder, String requisitionInitiatorId, String password, ContractManager contractManager, String contractManagerEmail, String vendorDuns) {
145 
146         StringBuffer cxml = new StringBuffer();
147         Date d = SpringContext.getBean(DateTimeService.class).getCurrentDate();
148         SimpleDateFormat date = PurApDateFormatUtils.getSimpleDateFormat(PurapConstants.NamedDateFormats.CXML_SIMPLE_DATE_FORMAT);
149         SimpleDateFormat time = PurApDateFormatUtils.getSimpleDateFormat(PurapConstants.NamedDateFormats.CXML_SIMPLE_TIME_FORMAT);
150 
151         cxml.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
152         cxml.append("<!DOCTYPE cXML SYSTEM \"http://xml.cXML.org/schemas/cXML/1.2.019/cXML.dtd\">\n");
153         // payloadID - can be whatever you would like it to be. Just make it unique.
154         cxml.append("<cXML payloadID=\"test@kuali.org\" timestamp=\"").append(date.format(d)).append("T").append(time.format(d)).append("+03:00").append("\" xml:lang=\"en-US\">\n");
155         cxml.append("  <Header>\n");
156         cxml.append("    <From>\n");
157         cxml.append("      <Credential domain=\"NetworkUserId\">\n");
158         cxml.append("        <Identity>").append(requisitionInitiatorId.toUpperCase()).append("</Identity>\n");
159         cxml.append("      </Credential>\n");
160         cxml.append("    </From>\n");
161         cxml.append("    <To>\n");
162         cxml.append("      <Credential domain=\"DUNS\">\n");
163         cxml.append("        <Identity>").append(vendorDuns).append("</Identity>\n");
164         cxml.append("      </Credential>\n");
165         cxml.append("    </To>\n");
166         cxml.append("    <Sender>\n");
167         cxml.append("      <Credential domain=\"NetworkUserId\">\n");
168         cxml.append("        <Identity>OLE</Identity>\n");
169         cxml.append("        <SharedSecret>").append(password).append("</SharedSecret>\n");
170         cxml.append("      </Credential>\n");
171         cxml.append("      <UserAgent>Ariba.com Network V1.0</UserAgent>\n");
172         cxml.append("    </Sender>\n");
173         cxml.append("  </Header>\n");
174         // set deployment mode to test if not in production
175         if (isProduction()) {
176             cxml.append("  <Request>\n");
177         } else {
178             cxml.append("  <Request deploymentMode=\"test\">\n");
179         }
180         cxml.append("    <OrderRequest>\n");
181         cxml.append("      <OrderRequestHeader orderID=\"").append(purchaseOrder.getPurapDocumentIdentifier()).append("\" orderDate=\"").append(date.format(d)).append("\" type=\"new\">\n");
182         cxml.append("        <Total>\n");
183         cxml.append("          <Money currency=\"USD\">").append(purchaseOrder.getTotalDollarAmount()).append("</Money>\n");
184         cxml.append("        </Total>\n");
185 
186 
187         cxml.append("        <ShipTo>\n");
188         cxml.append("          <Address addressID=\"").append(purchaseOrder.getDeliveryCampusCode()).append(purchaseOrder.getOrganizationCode()).append("\">\n");
189         cxml.append("            <Name xml:lang=\"en\">Kuali</Name>\n");
190         cxml.append("            <PostalAddress name=\"defaul\">\n");
191         cxml.append("              <DeliverTo>").append(purchaseOrder.getDeliveryToName().trim()).append("</DeliverTo>\n");
192         if (StringUtils.isNotEmpty(purchaseOrder.getInstitutionContactEmailAddress())) {
193             cxml.append("              <DeliverTo><![CDATA[").append(purchaseOrder.getInstitutionContactEmailAddress()).append("]]></DeliverTo>\n");
194         } else {
195             cxml.append("              <DeliverTo><![CDATA[").append(purchaseOrder.getRequestorPersonEmailAddress()).append("]]></DeliverTo>\n");
196         }
197         if (StringUtils.isNotEmpty(purchaseOrder.getInstitutionContactPhoneNumber())) {
198             cxml.append("              <DeliverTo><![CDATA[").append(purchaseOrder.getInstitutionContactPhoneNumber()).append("]]></DeliverTo>\n");
199         } else {
200             cxml.append("              <DeliverTo><![CDATA[").append(purchaseOrder.getRequestorPersonPhoneNumber()).append("]]></DeliverTo>\n");
201         }
202 
203         //check indicator to decide if receiving or delivery address should be sent to the vendor
204         if (purchaseOrder.getAddressToVendorIndicator()) {  //use receiving address
205             if (StringUtils.isNotEmpty(purchaseOrder.getReceivingName())) {
206                 cxml.append("              <DeliverTo><![CDATA[").append(purchaseOrder.getReceivingName()).append("]]></DeliverTo>\n");
207             }
208             cxml.append("              <Street><![CDATA[").append(purchaseOrder.getReceivingLine1Address().trim()).append("]]></Street>\n");
209             if (StringUtils.isNotEmpty(purchaseOrder.getReceivingLine2Address())) {
210                 cxml.append("              <Street><![CDATA[").append(purchaseOrder.getReceivingLine2Address().trim()).append("]]></Street>\n");
211             }
212             cxml.append("              <City><![CDATA[").append(purchaseOrder.getReceivingCityName().trim()).append("]]></City>\n");
213             cxml.append("              <State>").append(purchaseOrder.getReceivingStateCode()).append("</State>\n");
214             cxml.append("              <PostalCode>").append(purchaseOrder.getReceivingPostalCode()).append("</PostalCode>\n");
215             cxml.append("              <Country isoCountryCode=\"").append(purchaseOrder.getReceivingCountryCode()).append("\">").append(purchaseOrder.getReceivingCountryCode()).append("</Country>\n");
216         } else { //use final delivery address
217             if (StringUtils.isNotEmpty(purchaseOrder.getDeliveryBuildingName())) {
218                 cxml.append("              <DeliverTo><![CDATA[").append(purchaseOrder.getDeliveryBuildingName()).append(" (").append(purchaseOrder.getDeliveryBuildingCode()).append(")]]></DeliverTo>\n");
219             }
220             cxml.append("              <Street><![CDATA[").append(purchaseOrder.getDeliveryBuildingLine1Address().trim()).append("]]></Street>\n");
221             if (StringUtils.isNotEmpty(purchaseOrder.getDeliveryBuildingLine2Address())) {
222                 cxml.append("              <Street><![CDATA[").append(purchaseOrder.getDeliveryBuildingLine2Address().trim()).append("]]></Street>\n");
223             }
224             if (StringUtils.isNotEmpty(purchaseOrder.getDeliveryBuildingRoomNumber())) {
225                 cxml.append("              <Street><![CDATA[").append(purchaseOrder.getDeliveryBuildingRoomNumber().trim()).append("]]></Street>\n");
226             }
227             cxml.append("              <City><![CDATA[").append(purchaseOrder.getDeliveryCityName().trim()).append("]]></City>\n");
228             cxml.append("              <State>").append(purchaseOrder.getDeliveryStateCode()).append("</State>\n");
229             cxml.append("              <PostalCode>").append(purchaseOrder.getDeliveryPostalCode()).append("</PostalCode>\n");
230             cxml.append("              <Country isoCountryCode=\"").append(purchaseOrder.getDeliveryCountryCode()).append("\">").append(purchaseOrder.getDeliveryCountryName()).append("</Country>\n");
231         }
232         cxml.append("            </PostalAddress>\n");
233         cxml.append("          </Address>\n");
234         cxml.append("        </ShipTo>\n");
235 
236 
237         cxml.append("        <BillTo>\n");
238         cxml.append("          <Address addressID=\"").append(purchaseOrder.getDeliveryCampusCode()).append("\">\n");
239         cxml.append("            <Name xml:lang=\"en\"><![CDATA[").append(purchaseOrder.getBillingName().trim()).append("]]></Name>\n");
240         cxml.append("            <PostalAddress name=\"defaul\">\n");
241         cxml.append("              <Street><![CDATA[").append(purchaseOrder.getBillingLine1Address().trim()).append("]]></Street>\n");
242         if (StringUtils.isNotEmpty(purchaseOrder.getBillingLine2Address())) {
243             cxml.append("              <Street><![CDATA[").append(purchaseOrder.getBillingLine2Address().trim()).append("]]></Street>\n");
244         }
245         cxml.append("              <City><![CDATA[").append(purchaseOrder.getBillingCityName().trim()).append("]]></City>\n");
246         cxml.append("              <State>").append(purchaseOrder.getBillingStateCode()).append("</State>\n");
247         cxml.append("              <PostalCode>").append(purchaseOrder.getBillingPostalCode()).append("</PostalCode>\n");
248         cxml.append("              <Country isoCountryCode=\"").append(purchaseOrder.getBillingCountryCode()).append("\">").append(purchaseOrder.getBillingCountryName()).append("</Country>\n");
249         cxml.append("            </PostalAddress>\n");
250         cxml.append("          </Address>\n");
251         cxml.append("        </BillTo>\n");
252         cxml.append("        <Tax>\n");
253         cxml.append("          <Money currency=\"USD\">").append(purchaseOrder.getTotalTaxAmount()).append("</Money>\n");
254         cxml.append("          <Description xml:lang=\"en\">").append("tax description").append("</Description>\n");
255         cxml.append("        </Tax>\n");
256         cxml.append("        <Extrinsic name=\"username\">").append(requisitionInitiatorId.toUpperCase()).append("</Extrinsic>\n");
257         cxml.append("        <Extrinsic name=\"BuyerPhone\">").append(contractManager.getContractManagerPhoneNumber()).append("</Extrinsic>\n");
258         cxml.append("        <Extrinsic name=\"SupplierNumber\">").append(purchaseOrder.getVendorNumber()).append("</Extrinsic>\n");
259         cxml.append("      </OrderRequestHeader>\n");
260 
261         for (Object tmpPoi : purchaseOrder.getItems()) {
262             PurchaseOrderItem poi = (PurchaseOrderItem) tmpPoi;
263             cxml.append("      <ItemOut quantity=\"").append(poi.getItemQuantity()).append("\" lineNumber=\"").append(poi.getItemLineNumber()).append("\">\n");
264             cxml.append("        <ItemID>\n");
265             cxml.append("          <SupplierPartID><![CDATA[").append(poi.getItemCatalogNumber()).append("]]></SupplierPartID>\n");
266             if (ObjectUtils.isNotNull(poi.getItemAuxiliaryPartIdentifier())) {
267                 cxml.append("          <SupplierPartAuxiliaryID><![CDATA[").append(poi.getItemAuxiliaryPartIdentifier()).append("]]></SupplierPartAuxiliaryID>\n");
268             }
269             cxml.append("        </ItemID>\n");
270             cxml.append("        <ItemDetail>\n");
271             cxml.append("          <UnitPrice>\n");
272             cxml.append("            <Money currency=\"USD\">").append(poi.getItemUnitPrice()).append("</Money>\n");
273             cxml.append("          </UnitPrice>\n");
274             cxml.append("          <Description xml:lang=\"en\"><![CDATA[").append(poi.getItemDescription()).append("]]></Description>\n"); // Required.
275             cxml.append("          <UnitOfMeasure><![CDATA[").append(poi.getItemUnitOfMeasureCode()).append("]]></UnitOfMeasure>\n");
276             cxml.append("          <Classification domain=\"UNSPSC\"></Classification>\n");
277             if (poi.getExternalOrganizationB2bProductTypeName().equals("Punchout")) {
278                 cxml.append("          <ManufacturerPartID></ManufacturerPartID>\n");
279             } else {
280                 cxml.append("          <ManufacturerPartID>").append(poi.getExternalOrganizationB2bProductReferenceNumber()).append("</ManufacturerPartID>\n");
281             }
282             cxml.append("          <ManufacturerName>").append(poi.getExternalOrganizationB2bProductTypeName()).append("</ManufacturerName>\n");
283             cxml.append("        </ItemDetail>\n");
284             cxml.append("      </ItemOut>\n");
285         }
286 
287         cxml.append("    </OrderRequest>\n");
288         cxml.append("  </Request>\n");
289         cxml.append("</cXML>");
290 
291         if (LOG.isDebugEnabled()) {
292             LOG.debug("getCxml(): cXML for po number " + purchaseOrder.getPurapDocumentIdentifier() + ":\n" + cxml.toString());
293         }
294 
295         return cxml.toString();
296     }
297 
298     /**
299      * @see org.kuali.ole.module.purap.document.service.B2BPurchaseOrderService#verifyCxmlPOData(org.kuali.ole.module.purap.document.PurchaseOrderDocument,
300      *      org.kuali.rice.kim.api.identity.Person, java.lang.String, org.kuali.ole.vnd.businessobject.ContractManager,
301      *      java.lang.String, java.lang.String)
302      */
303     public String verifyCxmlPOData(PurchaseOrderDocument purchaseOrder, String requisitionInitiatorId, String password, ContractManager contractManager, String contractManagerEmail, String vendorDuns) {
304         StringBuffer errors = new StringBuffer();
305 
306         if (ObjectUtils.isNull(purchaseOrder)) {
307             LOG.error("verifyCxmlPOData()  The Purchase Order is null.");
308             errors.append("Error occurred retrieving Purchase Order\n");
309             return errors.toString();
310         }
311         if (ObjectUtils.isNull(contractManager)) {
312             LOG.error("verifyCxmlPOData()  The contractManager is null.");
313             errors.append("Error occurred retrieving Contract Manager\n");
314             return errors.toString();
315         }
316         if (StringUtils.isEmpty(password)) {
317             LOG.error("verifyCxmlPOData()  The B2B PO password is required for the cXML PO but is missing.");
318             errors.append("Missing Data: B2B PO password\n");
319         }
320         if (ObjectUtils.isNull(purchaseOrder.getPurapDocumentIdentifier())) {
321             LOG.error("verifyCxmlPOData()  The purchase order Id is required for the cXML PO but is missing.");
322             errors.append("Missing Data: Purchase Order ID\n");
323         }
324         if (StringUtils.isEmpty(requisitionInitiatorId)) {
325             LOG.error("verifyCxmlPOData()  The requisition initiator Network Id is required for the cXML PO but is missing.");
326             errors.append("Missing Data: Requisition Initiator NetworkId\n");
327         }
328         if (ObjectUtils.isNull(purchaseOrder.getPurchaseOrderCreateTimestamp())) {
329             LOG.error("verifyCxmlPOData()  The PO create date is required for the cXML PO but is null.");
330             errors.append("Create Date\n");
331         }
332         if (StringUtils.isEmpty(contractManager.getContractManagerPhoneNumber())) {
333             LOG.error("verifyCxmlPOData()  The contract manager phone number is required for the cXML PO but is missing.");
334             errors.append("Missing Data: Contract Manager Phone Number\n");
335         }
336         if (StringUtils.isEmpty(contractManager.getContractManagerName())) {
337             LOG.error("verifyCxmlPOData()  The contract manager name is required for the cXML PO but is missing.");
338             errors.append("Missing Data: Contract Manager Name\n");
339         }
340         if (StringUtils.isEmpty(purchaseOrder.getDeliveryCampusCode())) {
341             LOG.error("verifyCxmlPOData()  The Delivery Campus Code is required for the cXML PO but is missing.");
342             errors.append("Missing Data: Delivery Campus Code\n");
343         }
344         if (StringUtils.isEmpty(purchaseOrder.getBillingName())) {
345             LOG.error("verifyCxmlPOData()  The Delivery Billing Name is required for the cXML PO but is missing.");
346             errors.append("Missing Data: Delivery Billing Name\n");
347         }
348         if (StringUtils.isEmpty(purchaseOrder.getBillingLine1Address())) {
349             LOG.error("verifyCxmlPOData()  The Billing Line 1 Address is required for the cXML PO but is missing.");
350             errors.append("Missing Data: Billing Line 1 Address\n");
351         }
352         if (StringUtils.isEmpty(purchaseOrder.getBillingLine2Address())) {
353             LOG.error("verifyCxmlPOData()  The Billing Line 2 Address is required for the cXML PO but is missing.");
354             errors.append("Missing Data: Billing Line 2 Address\n");
355         }
356         if (StringUtils.isEmpty(purchaseOrder.getBillingCityName())) {
357             LOG.error("verifyCxmlPOData()  The Billing Address City Name is required for the cXML PO but is missing.");
358             errors.append("Missing Data: Billing Address City Name\n");
359         }
360         if (StringUtils.isEmpty(purchaseOrder.getBillingStateCode())) {
361             LOG.error("verifyCxmlPOData()  The Billing Address State Code is required for the cXML PO but is missing.");
362             errors.append("Missing Data: Billing Address State Code\n");
363         }
364         if (StringUtils.isEmpty(purchaseOrder.getBillingPostalCode())) {
365             LOG.error("verifyCxmlPOData()  The Billing Address Postal Code is required for the cXML PO but is missing.");
366             errors.append("Missing Data: Billing Address Postal Code\n");
367         }
368         if (StringUtils.isEmpty(purchaseOrder.getDeliveryToName())) {
369             LOG.error("verifyCxmlPOData()  The Delivery To Name is required for the cXML PO but is missing.");
370             errors.append("Missing Data: Delivery To Name\n");
371         }
372         if (StringUtils.isEmpty(contractManagerEmail)) {
373             LOG.error("verifyCxmlPOData()  The Contract Manager Email is required for the cXML PO but is missing.");
374             errors.append("Missing Data: Contract Manager Email\n");
375         }
376         if (StringUtils.isEmpty(purchaseOrder.getDeliveryToEmailAddress())) {
377             LOG.error("verifyCxmlPOData()  The Requesting Person Email Address is required for the cXML PO but is missing.");
378             errors.append("Missing Data: Requesting Person Email Address\n");
379         }
380         if (StringUtils.isEmpty(purchaseOrder.getDeliveryToPhoneNumber())) {
381             LOG.error("verifyCxmlPOData()  The Requesting Person Phone Number is required for the cXML PO but is missing.");
382             errors.append("Missing Data: Requesting Person Phone Number\n");
383         }
384         if (StringUtils.isEmpty(purchaseOrder.getDeliveryBuildingLine1Address())) {
385             LOG.error("verifyCxmlPOData()  The Delivery Line 1 Address is required for the cXML PO but is missing.");
386             errors.append("Missing Data: Delivery Line 1 Address\n");
387         }
388         if (StringUtils.isEmpty(purchaseOrder.getDeliveryToName())) {
389             LOG.error("verifyCxmlPOData()  The Delivery To Name is required for the cXML PO but is missing.");
390             errors.append("Missing Data: Delivery To Name\n");
391         }
392         if (StringUtils.isEmpty(purchaseOrder.getDeliveryCityName())) {
393             LOG.error("verifyCxmlPOData()  The Delivery City Name is required for the cXML PO but is missing.");
394             errors.append("Missing Data: Delivery City Name\n");
395         }
396         if (StringUtils.isEmpty(purchaseOrder.getDeliveryStateCode())) {
397             LOG.error("verifyCxmlPOData()  The Delivery State is required for the cXML PO but is missing.");
398             errors.append("Missing Data: Delivery State\n");
399         }
400         if (StringUtils.isEmpty(purchaseOrder.getDeliveryPostalCode())) {
401             LOG.error("verifyCxmlPOData()  The Delivery Postal Code is required for the cXML PO but is missing.");
402             errors.append("Missing Data: Delivery Postal Code\n");
403         }
404 
405         // verify item data
406         List detailList = purchaseOrder.getItems();
407         for (Iterator iter = detailList.iterator(); iter.hasNext(); ) {
408             PurchaseOrderItem poi = (PurchaseOrderItem) iter.next();
409             if (ObjectUtils.isNotNull(poi.getItemType()) && poi.getItemType().isLineItemIndicator()) {
410                 if (ObjectUtils.isNull(poi.getItemLineNumber())) {
411                     LOG.error("verifyCxmlPOData()  The Item Line Number is required for the cXML PO but is missing.");
412                     errors.append("Missing Data: Item Line Number\n");
413                 }
414                 if (StringUtils.isEmpty(poi.getItemCatalogNumber())) {
415                     LOG.error("verifyCxmlPOData()  The Catalog Number for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
416                     errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Catalog Number\n");
417                 }
418                 if (StringUtils.isEmpty(poi.getItemDescription())) {
419                     LOG.error("verifyCxmlPOData()  The Description for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
420                     errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Description\n");
421                 }
422                 if (StringUtils.isEmpty(poi.getItemUnitOfMeasureCode())) {
423                     LOG.error("verifyCxmlPOData()  The Unit Of Measure Code for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
424                     errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Unit Of Measure\n");
425                 }
426                 if (StringUtils.isEmpty(poi.getExternalOrganizationB2bProductTypeName())) {
427                     LOG.error("verifyCxmlPOData()  The External Org B2B Product Type Name for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
428                     errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - External Org B2B Product Type Name\n");
429                 }
430                 if (poi.getItemQuantity() == null) {
431                     LOG.error("verifyCxmlPOData()  The Order Quantity for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
432                     errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Order Quantity\n");
433                 }
434                 if (poi.getItemUnitPrice() == null) {
435                     LOG.error("verifyCxmlPOData()  The Unit Price for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
436                     errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Unit Price\n");
437                 }
438             }
439         } // end item looping
440 
441         return errors.toString();
442     }
443 
444     /**
445      * Retrieve the Contract Manager's email
446      */
447     protected String getContractManagerEmail(ContractManager cm) {
448         Person contractManager = getPersonService().getPerson(cm.getContractManagerUserIdentifier());
449         if (ObjectUtils.isNotNull(contractManager)) {
450             return contractManager.getEmailAddressUnmasked();
451         }
452         return "";
453     }
454 
455     /**
456      * @return Returns the personService.
457      */
458     protected PersonService getPersonService() {
459         if (personService == null)
460             personService = SpringContext.getBean(PersonService.class);
461         return personService;
462     }
463 
464     public void setRequisitionService(RequisitionService requisitionService) {
465         this.requisitionService = requisitionService;
466     }
467 
468     public void setParameterService(ParameterService parameterService) {
469         this.parameterService = parameterService;
470     }
471 
472     public void setB2bDao(B2BDao b2bDao) {
473         this.b2bDao = b2bDao;
474     }
475 
476     /**
477      * Throws an exception if running on production
478      */
479     protected boolean isProduction() {
480         ConfigurationService configService = SpringContext.getBean(ConfigurationService.class);
481         return StringUtils.equals(configService.getPropertyValueAsString(OLEConstants.PROD_ENVIRONMENT_CODE_KEY), b2bEnvironment);
482     }
483 
484     public void setB2bEnvironment(String environment) {
485         b2bEnvironment = environment;
486     }
487 
488     public void setB2bUserAgent(String userAgent) {
489         b2bUserAgent = userAgent;
490     }
491 
492     public void setB2bPurchaseOrderURL(String purchaseOrderURL) {
493         b2bPurchaseOrderURL = purchaseOrderURL;
494     }
495 
496     public void setB2bPurchaseOrderIdentity(String b2bPurchaseOrderIdentity) {
497         this.b2bPurchaseOrderIdentity = b2bPurchaseOrderIdentity;
498     }
499 
500     public void setB2bPurchaseOrderPassword(String purchaseOrderPassword) {
501         b2bPurchaseOrderPassword = purchaseOrderPassword;
502     }
503 
504 }
505