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.KFSConstants;
037 import org.kuali.kfs.sys.context.SpringContext;
038 import org.kuali.kfs.vnd.businessobject.ContractManager;
039 import org.kuali.rice.kim.bo.Person;
040 import org.kuali.rice.kim.service.PersonService;
041 import org.kuali.rice.kns.service.DateTimeService;
042 import org.kuali.rice.kns.service.KualiConfigurationService;
043 import org.kuali.rice.kns.service.ParameterService;
044 import org.kuali.rice.kns.util.ObjectUtils;
045 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
046 import org.springframework.transaction.annotation.Transactional;
047
048 @Transactional
049 public class B2BPurchaseOrderServiceImpl implements B2BPurchaseOrderService {
050 private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(B2BPurchaseOrderServiceImpl.class);
051
052 private B2BDao b2bDao;
053 private RequisitionService requisitionService;
054 private ParameterService parameterService;
055 private PersonService<Person> personService;
056
057 // injected values
058 private String b2bEnvironment;
059 private String b2bUserAgent;
060 private String b2bPurchaseOrderURL;
061 private String b2bPurchaseOrderIdentity;
062 private String b2bPurchaseOrderPassword;
063
064 /**
065 * @see org.kuali.kfs.module.purap.document.service.B2BPurchaseOrderService#sendPurchaseOrder(org.kuali.kfs.module.purap.document.PurchaseOrderDocument)
066 */
067 public String sendPurchaseOrder(PurchaseOrderDocument purchaseOrder) {
068 /*
069 * IMPORTANT DESIGN NOTE: We need the contract manager's name, phone number, and e-mail address. B2B orders that don't
070 * 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
071 * always get the contract manager from the B2B contract associated with the order, and for B2B orders to ignore the
072 * contract manager field on the PO. We pull the name and phone number from the contract manager table and get the e-mail
073 * address from the user data.
074 */
075
076 ContractManager contractManager = purchaseOrder.getVendorContract().getContractManager();
077 String contractManagerEmail = getContractManagerEmail(contractManager);
078
079 String vendorDuns = purchaseOrder.getVendorDetail().getVendorDunsNumber();
080
081 RequisitionDocument r = requisitionService.getRequisitionById(purchaseOrder.getRequisitionIdentifier());
082 KualiWorkflowDocument reqWorkflowDoc = r.getDocumentHeader().getWorkflowDocument();
083
084 LOG.debug("sendPurchaseOrder(): b2bPurchaseOrderURL is " + b2bPurchaseOrderURL);
085
086 String validateErrors = verifyCxmlPOData(purchaseOrder, reqWorkflowDoc.getInitiatorNetworkId(), b2bPurchaseOrderPassword, contractManager, contractManagerEmail, vendorDuns);
087 if (StringUtils.isEmpty(validateErrors)) {
088 return validateErrors;
089 }
090
091 StringBuffer transmitErrors = new StringBuffer();
092
093 try {
094 LOG.debug("sendPurchaseOrder() Generating cxml");
095 String cxml = getCxml(purchaseOrder, reqWorkflowDoc.getInitiatorNetworkId(), b2bPurchaseOrderPassword, contractManager, contractManagerEmail, vendorDuns);
096
097 LOG.info("sendPurchaseOrder() Sending cxml\n" + cxml);
098 String responseCxml = b2bDao.sendPunchOutRequest(cxml, b2bPurchaseOrderURL);
099
100 LOG.info("sendPurchaseOrder(): Response cXML for po #" + purchaseOrder.getPurapDocumentIdentifier() + ":\n" + responseCxml);
101
102 PurchaseOrderResponse poResponse = B2BParserHelper.getInstance().parsePurchaseOrderResponse(responseCxml);
103 String statusText = poResponse.getStatusText();
104 LOG.debug("sendPurchaseOrder(): statusText is " + statusText);
105 if ((ObjectUtils.isNull(statusText)) || (!"success".equalsIgnoreCase(statusText.trim()))) {
106 LOG.error("sendPurchaseOrder(): PO cXML for po number " + purchaseOrder.getPurapDocumentIdentifier() + " failed sending to vendor: " + statusText);
107 transmitErrors.append("Unable to send Purchase Order: " + statusText);
108
109 // find any additional error messages that might have been sent
110 List errorMessages = poResponse.getPOResponseErrorMessages();
111 if (ObjectUtils.isNotNull(errorMessages) && !errorMessages.isEmpty()) {
112 for (Iterator iter = errorMessages.iterator(); iter.hasNext();) {
113 String errorMessage = (String) iter.next();
114 if (ObjectUtils.isNotNull(errorMessage)) {
115 LOG.error("sendPurchaseOrder(): Error message for po number " + purchaseOrder.getPurapDocumentIdentifier() + ": " + errorMessage);
116 transmitErrors.append("Error sending Purchase Order: " + errorMessage);
117 }
118 }
119 }
120 }
121 }
122 catch (B2BConnectionException e) {
123 LOG.error("sendPurchaseOrder() Error connecting to b2b", e);
124 transmitErrors.append("Connection to vendor failed.");
125 }
126 catch (CxmlParseError e) {
127 LOG.error("sendPurchaseOrder() Error Parsing", e);
128 transmitErrors.append("Unable to read cxml returned from vendor.");
129 }
130 catch (Throwable e) {
131 LOG.error("sendPurchaseOrder() Unknown Error", e);
132 transmitErrors.append("Unexpected error occurred while attempting to transmit Purchase Order.");
133 }
134
135 return transmitErrors.toString();
136 }
137
138 /**
139 * @see org.kuali.kfs.module.purap.document.service.B2BPurchaseOrderService#getCxml(org.kuali.kfs.module.purap.document.PurchaseOrderDocument,
140 * org.kuali.rice.kim.bo.Person, java.lang.String, org.kuali.kfs.vnd.businessobject.ContractManager,
141 * java.lang.String, java.lang.String)
142 */
143 public String getCxml(PurchaseOrderDocument purchaseOrder, String requisitionInitiatorId, String password, ContractManager contractManager, String contractManagerEmail, String vendorDuns) {
144
145 StringBuffer cxml = new StringBuffer();
146 Date d = SpringContext.getBean(DateTimeService.class).getCurrentDate();
147 SimpleDateFormat date = PurApDateFormatUtils.getSimpleDateFormat(PurapConstants.NamedDateFormats.CXML_SIMPLE_DATE_FORMAT);
148 SimpleDateFormat time = PurApDateFormatUtils.getSimpleDateFormat(PurapConstants.NamedDateFormats.CXML_SIMPLE_TIME_FORMAT);
149
150 cxml.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
151 cxml.append("<!DOCTYPE cXML SYSTEM \"http://xml.cXML.org/schemas/cXML/1.2.019/cXML.dtd\">\n");
152 // payloadID - can be whatever you would like it to be. Just make it unique.
153 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");
154 cxml.append(" <Header>\n");
155 cxml.append(" <From>\n");
156 cxml.append(" <Credential domain=\"NetworkUserId\">\n");
157 cxml.append(" <Identity>").append(requisitionInitiatorId.toUpperCase()).append("</Identity>\n");
158 cxml.append(" </Credential>\n");
159 cxml.append(" </From>\n");
160 cxml.append(" <To>\n");
161 cxml.append(" <Credential domain=\"DUNS\">\n");
162 cxml.append(" <Identity>").append(vendorDuns).append("</Identity>\n");
163 cxml.append(" </Credential>\n");
164 cxml.append(" </To>\n");
165 cxml.append(" <Sender>\n");
166 cxml.append(" <Credential domain=\"NetworkUserId\">\n");
167 cxml.append(" <Identity>").append(b2bPurchaseOrderIdentity).append("</Identity>\n");
168 cxml.append(" <SharedSecret>").append(password).append("</SharedSecret>\n");
169 cxml.append(" </Credential>\n");
170 cxml.append(" <UserAgent>Ariba.com Network V1.0</UserAgent>\n");
171 cxml.append(" </Sender>\n");
172 cxml.append(" </Header>\n");
173 // set deployment mode to test if not in production
174 if (isProduction()) {
175 cxml.append(" <Request>\n");
176 } else {
177 cxml.append(" <Request deploymentMode=\"test\">\n");
178 }
179 cxml.append(" <OrderRequest>\n");
180 cxml.append(" <OrderRequestHeader orderID=\"").append(purchaseOrder.getPurapDocumentIdentifier()).append("\" orderDate=\"").append(date.format(d)).append("\" type=\"new\">\n");
181 cxml.append(" <Total>\n");
182 cxml.append(" <Money currency=\"USD\">").append(purchaseOrder.getTotalDollarAmount()).append("</Money>\n");
183 cxml.append(" </Total>\n");
184
185
186 cxml.append(" <ShipTo>\n");
187 cxml.append(" <Address addressID=\"").append(purchaseOrder.getDeliveryCampusCode()).append(purchaseOrder.getOrganizationCode()).append("\">\n");
188 cxml.append(" <Name xml:lang=\"en\">Kuali</Name>\n");
189 cxml.append(" <PostalAddress name=\"defaul\">\n");
190 cxml.append(" <DeliverTo>").append(purchaseOrder.getDeliveryToName().trim()).append("</DeliverTo>\n");
191 if (StringUtils.isNotEmpty(purchaseOrder.getInstitutionContactEmailAddress())) {
192 cxml.append(" <DeliverTo><![CDATA[").append(purchaseOrder.getInstitutionContactEmailAddress()).append("]]></DeliverTo>\n");
193 }
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 }
200 else {
201 cxml.append(" <DeliverTo><![CDATA[").append(purchaseOrder.getRequestorPersonPhoneNumber()).append("]]></DeliverTo>\n");
202 }
203
204 //check indicator to decide if receiving or delivery address should be sent to the vendor
205 if (purchaseOrder.getAddressToVendorIndicator()) { //use receiving address
206 if (StringUtils.isNotEmpty(purchaseOrder.getReceivingName())) {
207 cxml.append(" <DeliverTo><![CDATA[").append(purchaseOrder.getReceivingName()).append("]]></DeliverTo>\n");
208 }
209 cxml.append(" <Street><![CDATA[").append(purchaseOrder.getReceivingLine1Address().trim()).append("]]></Street>\n");
210 if (StringUtils.isNotEmpty(purchaseOrder.getReceivingLine2Address())) {
211 cxml.append(" <Street><![CDATA[").append(purchaseOrder.getReceivingLine2Address().trim()).append("]]></Street>\n");
212 }
213 cxml.append(" <City><![CDATA[").append(purchaseOrder.getReceivingCityName().trim()).append("]]></City>\n");
214 cxml.append(" <State>").append(purchaseOrder.getReceivingStateCode()).append("</State>\n");
215 cxml.append(" <PostalCode>").append(purchaseOrder.getReceivingPostalCode()).append("</PostalCode>\n");
216 cxml.append(" <Country isoCountryCode=\"").append(purchaseOrder.getReceivingCountryCode()).append("\">").append(purchaseOrder.getReceivingCountryCode()).append("</Country>\n");
217 }
218 else { //use final delivery address
219 if (StringUtils.isNotEmpty(purchaseOrder.getDeliveryBuildingName())) {
220 cxml.append(" <DeliverTo><![CDATA[").append(purchaseOrder.getDeliveryBuildingName()).append(" (").append(purchaseOrder.getDeliveryBuildingCode()).append(")]]></DeliverTo>\n");
221 }
222 cxml.append(" <Street><![CDATA[").append(purchaseOrder.getDeliveryBuildingLine1Address().trim()).append("]]></Street>\n");
223 if (StringUtils.isNotEmpty(purchaseOrder.getDeliveryBuildingLine2Address())) {
224 cxml.append(" <Street><![CDATA[").append(purchaseOrder.getDeliveryBuildingLine2Address().trim()).append("]]></Street>\n");
225 }
226 if (StringUtils.isNotEmpty(purchaseOrder.getDeliveryBuildingRoomNumber())) {
227 cxml.append(" <Street><![CDATA[").append(purchaseOrder.getDeliveryBuildingRoomNumber().trim()).append("]]></Street>\n");
228 }
229 cxml.append(" <City><![CDATA[").append(purchaseOrder.getDeliveryCityName().trim()).append("]]></City>\n");
230 cxml.append(" <State>").append(purchaseOrder.getDeliveryStateCode()).append("</State>\n");
231 cxml.append(" <PostalCode>").append(purchaseOrder.getDeliveryPostalCode()).append("</PostalCode>\n");
232 cxml.append(" <Country isoCountryCode=\"").append(purchaseOrder.getDeliveryCountryCode()).append("\">").append(purchaseOrder.getDeliveryCountryName()).append("</Country>\n");
233 }
234 cxml.append(" </PostalAddress>\n");
235 cxml.append(" </Address>\n");
236 cxml.append(" </ShipTo>\n");
237
238
239 cxml.append(" <BillTo>\n");
240 cxml.append(" <Address addressID=\"").append(purchaseOrder.getDeliveryCampusCode()).append("\">\n");
241 cxml.append(" <Name xml:lang=\"en\"><![CDATA[").append(purchaseOrder.getBillingName().trim()).append("]]></Name>\n");
242 cxml.append(" <PostalAddress name=\"defaul\">\n");
243 cxml.append(" <Street><![CDATA[").append(purchaseOrder.getBillingLine1Address().trim()).append("]]></Street>\n");
244 if (StringUtils.isNotEmpty(purchaseOrder.getBillingLine2Address())) {
245 cxml.append(" <Street><![CDATA[").append(purchaseOrder.getBillingLine2Address().trim()).append("]]></Street>\n");
246 }
247 cxml.append(" <City><![CDATA[").append(purchaseOrder.getBillingCityName().trim()).append("]]></City>\n");
248 cxml.append(" <State>").append(purchaseOrder.getBillingStateCode()).append("</State>\n");
249 cxml.append(" <PostalCode>").append(purchaseOrder.getBillingPostalCode()).append("</PostalCode>\n");
250 cxml.append(" <Country isoCountryCode=\"").append(purchaseOrder.getBillingCountryCode()).append("\">").append(purchaseOrder.getBillingCountryName()).append("</Country>\n");
251 cxml.append(" </PostalAddress>\n");
252 cxml.append(" </Address>\n");
253 cxml.append(" </BillTo>\n");
254 cxml.append(" <Tax>\n");
255 cxml.append(" <Money currency=\"USD\">").append(purchaseOrder.getTotalTaxAmount()).append("</Money>\n");
256 cxml.append(" <Description xml:lang=\"en\">").append("tax description").append("</Description>\n");
257 cxml.append(" </Tax>\n");
258 cxml.append(" <Extrinsic name=\"username\">").append(requisitionInitiatorId.toUpperCase()).append("</Extrinsic>\n");
259 cxml.append(" <Extrinsic name=\"BuyerPhone\">").append(contractManager.getContractManagerPhoneNumber()).append("</Extrinsic>\n");
260 cxml.append(" <Extrinsic name=\"SupplierNumber\">").append(purchaseOrder.getVendorNumber()).append("</Extrinsic>\n");
261 cxml.append(" </OrderRequestHeader>\n");
262
263 for (Object tmpPoi : purchaseOrder.getItems()) {
264 PurchaseOrderItem poi = (PurchaseOrderItem) tmpPoi;
265 cxml.append(" <ItemOut quantity=\"").append(poi.getItemQuantity()).append("\" lineNumber=\"").append(poi.getItemLineNumber()).append("\">\n");
266 cxml.append(" <ItemID>\n");
267 cxml.append(" <SupplierPartID><![CDATA[").append(poi.getItemCatalogNumber()).append("]]></SupplierPartID>\n");
268 if (ObjectUtils.isNotNull(poi.getItemAuxiliaryPartIdentifier())) {
269 cxml.append(" <SupplierPartAuxiliaryID><![CDATA[").append(poi.getItemAuxiliaryPartIdentifier()).append("]]></SupplierPartAuxiliaryID>\n");
270 }
271 cxml.append(" </ItemID>\n");
272 cxml.append(" <ItemDetail>\n");
273 cxml.append(" <UnitPrice>\n");
274 cxml.append(" <Money currency=\"USD\">").append(poi.getItemUnitPrice()).append("</Money>\n");
275 cxml.append(" </UnitPrice>\n");
276 cxml.append(" <Description xml:lang=\"en\"><![CDATA[").append(poi.getItemDescription()).append("]]></Description>\n"); // Required.
277 cxml.append(" <UnitOfMeasure><![CDATA[").append(poi.getItemUnitOfMeasureCode()).append("]]></UnitOfMeasure>\n");
278 cxml.append(" <Classification domain=\"UNSPSC\"></Classification>\n");
279 if (poi.getExternalOrganizationB2bProductTypeName().equals("Punchout")) {
280 cxml.append(" <ManufacturerPartID></ManufacturerPartID>\n");
281 }
282 else {
283 cxml.append(" <ManufacturerPartID>").append(poi.getExternalOrganizationB2bProductReferenceNumber()).append("</ManufacturerPartID>\n");
284 }
285 cxml.append(" <ManufacturerName>").append(poi.getExternalOrganizationB2bProductTypeName()).append("</ManufacturerName>\n");
286 cxml.append(" </ItemDetail>\n");
287 cxml.append(" </ItemOut>\n");
288 }
289
290 cxml.append(" </OrderRequest>\n");
291 cxml.append(" </Request>\n");
292 cxml.append("</cXML>");
293
294 LOG.debug("getCxml(): cXML for po number " + purchaseOrder.getPurapDocumentIdentifier() + ":\n" + cxml.toString());
295
296 return cxml.toString();
297 }
298
299 /**
300 * @see org.kuali.kfs.module.purap.document.service.B2BPurchaseOrderService#verifyCxmlPOData(org.kuali.kfs.module.purap.document.PurchaseOrderDocument,
301 * org.kuali.rice.kim.bo.Person, java.lang.String, org.kuali.kfs.vnd.businessobject.ContractManager,
302 * java.lang.String, java.lang.String)
303 */
304 public String verifyCxmlPOData(PurchaseOrderDocument purchaseOrder, String requisitionInitiatorId, String password, ContractManager contractManager, String contractManagerEmail, String vendorDuns) {
305 StringBuffer errors = new StringBuffer();
306
307 if (ObjectUtils.isNull(purchaseOrder)) {
308 LOG.error("verifyCxmlPOData() The Purchase Order is null.");
309 errors.append("Error occurred retrieving Purchase Order\n");
310 return errors.toString();
311 }
312 if (ObjectUtils.isNull(contractManager)) {
313 LOG.error("verifyCxmlPOData() The contractManager is null.");
314 errors.append("Error occurred retrieving Contract Manager\n");
315 return errors.toString();
316 }
317 if (StringUtils.isEmpty(password)) {
318 LOG.error("verifyCxmlPOData() The B2B PO password is required for the cXML PO but is missing.");
319 errors.append("Missing Data: B2B PO password\n");
320 }
321 if (ObjectUtils.isNull(purchaseOrder.getPurapDocumentIdentifier())) {
322 LOG.error("verifyCxmlPOData() The purchase order Id is required for the cXML PO but is missing.");
323 errors.append("Missing Data: Purchase Order ID\n");
324 }
325 if (StringUtils.isEmpty(requisitionInitiatorId)) {
326 LOG.error("verifyCxmlPOData() The requisition initiator Network Id is required for the cXML PO but is missing.");
327 errors.append("Missing Data: Requisition Initiator NetworkId\n");
328 }
329 if (ObjectUtils.isNull(purchaseOrder.getPurchaseOrderCreateTimestamp())) {
330 LOG.error("verifyCxmlPOData() The PO create date is required for the cXML PO but is null.");
331 errors.append("Create Date\n");
332 }
333 if (StringUtils.isEmpty(contractManager.getContractManagerPhoneNumber())) {
334 LOG.error("verifyCxmlPOData() The contract manager phone number is required for the cXML PO but is missing.");
335 errors.append("Missing Data: Contract Manager Phone Number\n");
336 }
337 if (StringUtils.isEmpty(contractManager.getContractManagerName())) {
338 LOG.error("verifyCxmlPOData() The contract manager name is required for the cXML PO but is missing.");
339 errors.append("Missing Data: Contract Manager Name\n");
340 }
341 if (StringUtils.isEmpty(purchaseOrder.getDeliveryCampusCode())) {
342 LOG.error("verifyCxmlPOData() The Delivery Campus Code is required for the cXML PO but is missing.");
343 errors.append("Missing Data: Delivery Campus Code\n");
344 }
345 if (StringUtils.isEmpty(purchaseOrder.getBillingName())) {
346 LOG.error("verifyCxmlPOData() The Delivery Billing Name is required for the cXML PO but is missing.");
347 errors.append("Missing Data: Delivery Billing Name\n");
348 }
349 if (StringUtils.isEmpty(purchaseOrder.getBillingLine1Address())) {
350 LOG.error("verifyCxmlPOData() The Billing Line 1 Address is required for the cXML PO but is missing.");
351 errors.append("Missing Data: Billing Line 1 Address\n");
352 }
353 if (StringUtils.isEmpty(purchaseOrder.getBillingLine2Address())) {
354 LOG.error("verifyCxmlPOData() The Billing Line 2 Address is required for the cXML PO but is missing.");
355 errors.append("Missing Data: Billing Line 2 Address\n");
356 }
357 if (StringUtils.isEmpty(purchaseOrder.getBillingCityName())) {
358 LOG.error("verifyCxmlPOData() The Billing Address City Name is required for the cXML PO but is missing.");
359 errors.append("Missing Data: Billing Address City Name\n");
360 }
361 if (StringUtils.isEmpty(purchaseOrder.getBillingStateCode())) {
362 LOG.error("verifyCxmlPOData() The Billing Address State Code is required for the cXML PO but is missing.");
363 errors.append("Missing Data: Billing Address State Code\n");
364 }
365 if (StringUtils.isEmpty(purchaseOrder.getBillingPostalCode())) {
366 LOG.error("verifyCxmlPOData() The Billing Address Postal Code is required for the cXML PO but is missing.");
367 errors.append("Missing Data: Billing Address Postal Code\n");
368 }
369 if (StringUtils.isEmpty(purchaseOrder.getDeliveryToName())) {
370 LOG.error("verifyCxmlPOData() The Delivery To Name is required for the cXML PO but is missing.");
371 errors.append("Missing Data: Delivery To Name\n");
372 }
373 if (StringUtils.isEmpty(contractManagerEmail)) {
374 LOG.error("verifyCxmlPOData() The Contract Manager Email is required for the cXML PO but is missing.");
375 errors.append("Missing Data: Contract Manager Email\n");
376 }
377 if (StringUtils.isEmpty(purchaseOrder.getDeliveryToEmailAddress())) {
378 LOG.error("verifyCxmlPOData() The Requesting Person Email Address is required for the cXML PO but is missing.");
379 errors.append("Missing Data: Requesting Person Email Address\n");
380 }
381 if (StringUtils.isEmpty(purchaseOrder.getDeliveryToPhoneNumber())) {
382 LOG.error("verifyCxmlPOData() The Requesting Person Phone Number is required for the cXML PO but is missing.");
383 errors.append("Missing Data: Requesting Person Phone Number\n");
384 }
385 if (StringUtils.isEmpty(purchaseOrder.getDeliveryBuildingLine1Address())) {
386 LOG.error("verifyCxmlPOData() The Delivery Line 1 Address is required for the cXML PO but is missing.");
387 errors.append("Missing Data: Delivery Line 1 Address\n");
388 }
389 if (StringUtils.isEmpty(purchaseOrder.getDeliveryToName())) {
390 LOG.error("verifyCxmlPOData() The Delivery To Name is required for the cXML PO but is missing.");
391 errors.append("Missing Data: Delivery To Name\n");
392 }
393 if (StringUtils.isEmpty(purchaseOrder.getDeliveryCityName())) {
394 LOG.error("verifyCxmlPOData() The Delivery City Name is required for the cXML PO but is missing.");
395 errors.append("Missing Data: Delivery City Name\n");
396 }
397 if (StringUtils.isEmpty(purchaseOrder.getDeliveryStateCode())) {
398 LOG.error("verifyCxmlPOData() The Delivery State is required for the cXML PO but is missing.");
399 errors.append("Missing Data: Delivery State\n");
400 }
401 if (StringUtils.isEmpty(purchaseOrder.getDeliveryPostalCode())) {
402 LOG.error("verifyCxmlPOData() The Delivery Postal Code is required for the cXML PO but is missing.");
403 errors.append("Missing Data: Delivery Postal Code\n");
404 }
405
406 // verify item data
407 List detailList = purchaseOrder.getItems();
408 for (Iterator iter = detailList.iterator(); iter.hasNext();) {
409 PurchaseOrderItem poi = (PurchaseOrderItem) iter.next();
410 if (ObjectUtils.isNotNull(poi.getItemType()) && poi.getItemType().isLineItemIndicator()) {
411 if (ObjectUtils.isNull(poi.getItemLineNumber())) {
412 LOG.error("verifyCxmlPOData() The Item Line Number is required for the cXML PO but is missing.");
413 errors.append("Missing Data: Item Line Number\n");
414 }
415 if (StringUtils.isEmpty(poi.getItemCatalogNumber())) {
416 LOG.error("verifyCxmlPOData() The Catalog Number for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
417 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Catalog Number\n");
418 }
419 if (StringUtils.isEmpty(poi.getItemDescription())) {
420 LOG.error("verifyCxmlPOData() The Description for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
421 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Description\n");
422 }
423 if (StringUtils.isEmpty(poi.getItemUnitOfMeasureCode())) {
424 LOG.error("verifyCxmlPOData() The Unit Of Measure Code for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
425 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Unit Of Measure\n");
426 }
427 if (StringUtils.isEmpty(poi.getExternalOrganizationB2bProductTypeName())) {
428 LOG.error("verifyCxmlPOData() The External Org B2B Product Type Name for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
429 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - External Org B2B Product Type Name\n");
430 }
431 if (poi.getItemQuantity() == null) {
432 LOG.error("verifyCxmlPOData() The Order Quantity for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
433 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Order Quantity\n");
434 }
435 if (poi.getItemUnitPrice() == null) {
436 LOG.error("verifyCxmlPOData() The Unit Price for item number " + poi.getItemLineNumber() + " is required for the cXML PO but is missing.");
437 errors.append("Missing Data: Item#" + poi.getItemLineNumber() + " - Unit Price\n");
438 }
439 }
440 } // end item looping
441
442 return errors.toString();
443 }
444
445 /**
446 * Retrieve the Contract Manager's email
447 */
448 protected String getContractManagerEmail(ContractManager cm) {
449 Person contractManager = getPersonService().getPerson(cm.getContractManagerUserIdentifier());
450 if (ObjectUtils.isNotNull(contractManager)) {
451 return contractManager.getEmailAddressUnmasked();
452 }
453 return "";
454 }
455
456 /**
457 * @return Returns the personService.
458 */
459 protected PersonService<Person> getPersonService() {
460 if(personService==null)
461 personService = SpringContext.getBean(PersonService.class);
462 return personService;
463 }
464
465 public void setRequisitionService(RequisitionService requisitionService) {
466 this.requisitionService = requisitionService;
467 }
468
469 public void setParameterService(ParameterService parameterService) {
470 this.parameterService = parameterService;
471 }
472
473 public void setB2bDao(B2BDao b2bDao) {
474 this.b2bDao = b2bDao;
475 }
476
477 /**
478 * Throws an exception if running on production
479 */
480 protected boolean isProduction() {
481 KualiConfigurationService configService = SpringContext.getBean(KualiConfigurationService.class);
482 return StringUtils.equals(configService.getPropertyString(KFSConstants.PROD_ENVIRONMENT_CODE_KEY), b2bEnvironment);
483 }
484
485 public void setB2bEnvironment(String environment) {
486 b2bEnvironment = environment;
487 }
488
489 public void setB2bUserAgent(String userAgent) {
490 b2bUserAgent = userAgent;
491 }
492
493 public void setB2bPurchaseOrderURL(String purchaseOrderURL) {
494 b2bPurchaseOrderURL = purchaseOrderURL;
495 }
496
497 public void setB2bPurchaseOrderIdentity(String b2bPurchaseOrderIdentity) {
498 this.b2bPurchaseOrderIdentity = b2bPurchaseOrderIdentity;
499 }
500
501 public void setB2bPurchaseOrderPassword(String purchaseOrderPassword) {
502 b2bPurchaseOrderPassword = purchaseOrderPassword;
503 }
504
505 }
506