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 }