001: /*
002: * $Id: PayPalEvents.java,v 1.4 2003/12/03 23:50:52 ajzeneski Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: *
024: */
025: package org.ofbiz.accounting.thirdparty.paypal;
026:
027: import java.io.BufferedReader;
028: import java.io.IOException;
029: import java.io.InputStreamReader;
030: import java.io.PrintWriter;
031: import java.net.URL;
032: import java.net.URLConnection;
033: import java.text.ParseException;
034: import java.text.SimpleDateFormat;
035: import java.util.*;
036:
037: import javax.servlet.ServletContext;
038: import javax.servlet.ServletRequest;
039: import javax.servlet.http.HttpServletRequest;
040: import javax.servlet.http.HttpServletResponse;
041:
042: import org.ofbiz.base.util.Debug;
043: import org.ofbiz.base.util.OrderedMap;
044: import org.ofbiz.base.util.UtilDateTime;
045: import org.ofbiz.base.util.UtilFormatOut;
046: import org.ofbiz.base.util.UtilHttp;
047: import org.ofbiz.base.util.UtilMisc;
048: import org.ofbiz.base.util.UtilProperties;
049: import org.ofbiz.entity.GenericDelegator;
050: import org.ofbiz.entity.GenericEntityException;
051: import org.ofbiz.entity.GenericValue;
052: import org.ofbiz.entity.transaction.GenericTransactionException;
053: import org.ofbiz.entity.transaction.TransactionUtil;
054: import org.ofbiz.order.order.OrderChangeHelper;
055: import org.ofbiz.product.catalog.CatalogWorker;
056: import org.ofbiz.product.store.ProductStoreWorker;
057: import org.ofbiz.service.GenericServiceException;
058: import org.ofbiz.service.LocalDispatcher;
059:
060: /**
061: * PayPal Events
062: *
063: * @author <a href="mailto:jaz@ofbiz.org">Andy Zeneski</a>
064: * @version $Revision: 1.4 $
065: * @since 2.0
066: */
067: public class PayPalEvents {
068:
069: public static final String module = PayPalEvents.class.getName();
070:
071: /** Initiate PayPal Request */
072: public static String callPayPal(HttpServletRequest request,
073: HttpServletResponse response) {
074: ServletContext application = ((ServletContext) request
075: .getAttribute("servletContext"));
076: GenericDelegator delegator = (GenericDelegator) request
077: .getAttribute("delegator");
078: LocalDispatcher dispatcher = (LocalDispatcher) request
079: .getAttribute("dispatcher");
080: GenericValue userLogin = (GenericValue) request.getSession()
081: .getAttribute("userLogin");
082:
083: // get the orderId
084: String orderId = (String) request.getAttribute("order_id");
085:
086: // get the order header
087: GenericValue orderHeader = null;
088: try {
089: orderHeader = delegator.findByPrimaryKey("OrderHeader",
090: UtilMisc.toMap("orderId", orderId));
091: } catch (GenericEntityException e) {
092: Debug.logError(e, "Cannot get the order header for order: "
093: + orderId, module);
094: request.setAttribute("_ERROR_MESSAGE_",
095: "<li>Problems getting order header.");
096: return "error";
097: }
098:
099: // get the order total
100: String orderTotal = UtilFormatOut.formatPrice(orderHeader
101: .getDouble("grandTotal"));
102:
103: // get the webSiteId
104: String webSiteId = CatalogWorker.getWebSiteId(request);
105:
106: // get the product store
107: GenericValue productStore = ProductStoreWorker
108: .getProductStore(request);
109:
110: if (productStore == null) {
111: Debug.logError("ProductStore is null", module);
112: request
113: .setAttribute("_ERROR_MESSAGE_",
114: "<li>Problems getting merchant configuration, please contact customer service.");
115: return "error";
116: }
117:
118: // get the payment properties file
119: GenericValue paymentConfig = ProductStoreWorker
120: .getProductStorePaymentSetting(delegator, productStore
121: .getString("productStoreId"), "EXT_PAYPAL",
122: null, true);
123: String configString = null;
124: if (paymentConfig != null) {
125: configString = paymentConfig
126: .getString("paymentPropertiesPath");
127: }
128:
129: if (configString == null) {
130: configString = "payment.properties";
131: }
132:
133: // get the company name
134: String company = UtilFormatOut.checkEmpty(productStore
135: .getString("companyName"), "");
136:
137: // create the item name
138: String itemName = "Order #" + orderId
139: + (company != null ? " from " + company : "");
140: String itemNumber = "0";
141:
142: // get the redirect url
143: String redirectUrl = UtilProperties.getPropertyValue(
144: configString, "payment.paypal.redirect");
145:
146: // get the notify url
147: String notifyUrl = UtilProperties.getPropertyValue(
148: configString, "payment.paypal.notify");
149:
150: // get the return urls
151: String returnUrl = UtilProperties.getPropertyValue(
152: configString, "payment.paypal.return");
153: String cancelReturnUrl = UtilProperties.getPropertyValue(
154: configString, "payment.paypal.cancelReturn");
155:
156: // get the image url
157: String imageUrl = UtilProperties.getPropertyValue(configString,
158: "payment.paypal.image");
159:
160: // get the paypal account
161: String payPalAccount = UtilProperties.getPropertyValue(
162: configString, "payment.paypal.business");
163:
164: // create the redirect string
165: Map parameters = new OrderedMap();
166: parameters.put("cmd", "_xclick");
167: parameters.put("business", payPalAccount);
168: parameters.put("item_name", itemName);
169: parameters.put("item_number", itemNumber);
170: parameters.put("invoice", orderId);
171: parameters.put("custom", userLogin.getString("userLoginId"));
172: parameters.put("amount", orderTotal);
173: parameters.put("return", returnUrl);
174: parameters.put("cancel_return", cancelReturnUrl);
175: parameters.put("notify_url", notifyUrl);
176: parameters.put("image_url", imageUrl);
177: parameters.put("no_note", "1"); // no notes allowed in paypal (not passed back)
178: parameters.put("no_shipping", "1"); // no shipping address required (local shipping used)
179:
180: String encodedParameters = UtilHttp.urlEncodeArgs(parameters);
181: String redirectString = redirectUrl + "?" + encodedParameters;
182:
183: // set the order in the session for cancelled orders
184: request.getSession().setAttribute("PAYPAL_ORDER", orderId);
185:
186: // redirect to paypal
187: try {
188: response.sendRedirect(redirectString);
189: } catch (IOException e) {
190: Debug.logError(e, "Problems redirecting to PayPal", module);
191: request
192: .setAttribute("_ERROR_MESSAGE_",
193: "<li>Problems connecting with PayPal, please contact customer service.");
194: return "error";
195: }
196:
197: return "success";
198: }
199:
200: /** PayPal Call-Back Event */
201: public static String payPalIPN(HttpServletRequest request,
202: HttpServletResponse response) {
203: ServletContext application = ((ServletContext) request
204: .getAttribute("servletContext"));
205: GenericDelegator delegator = (GenericDelegator) request
206: .getAttribute("delegator");
207: LocalDispatcher dispatcher = (LocalDispatcher) request
208: .getAttribute("dispatcher");
209:
210: // get the webSiteId
211: String webSiteId = CatalogWorker.getWebSiteId(request);
212:
213: // get the product store
214: GenericValue productStore = ProductStoreWorker
215: .getProductStore(request);
216:
217: // get the payment properties file
218: GenericValue paymentConfig = ProductStoreWorker
219: .getProductStorePaymentSetting(delegator, productStore
220: .getString("productStoreId"), "EXT_PAYPAL",
221: null, true);
222: String configString = null;
223: if (paymentConfig != null) {
224: configString = paymentConfig
225: .getString("paymentPropertiesPath");
226: }
227:
228: if (configString == null) {
229: configString = "payment.properties";
230: }
231:
232: // get the confirm URL
233: String confirmUrl = UtilProperties.getPropertyValue(
234: configString, "payment.paypal.confirm");
235: if (confirmUrl == null) {
236: Debug
237: .logError(
238: "Payment properties is not configured properly, no confirm URL defined!",
239: module);
240: request
241: .setAttribute("_ERROR_MESSAGE_",
242: "<li>PayPal has not been configured, please contact customer service.");
243: return "error";
244: }
245:
246: // first verify this is valid from PayPal
247: Map parametersMap = UtilHttp.getParameterMap(request);
248: parametersMap.put("cmd", "_notify-validate");
249:
250: // send off the confirm request
251: String confirmResp = null;
252:
253: try {
254: String str = UtilHttp.urlEncodeArgs(parametersMap);
255: URL u = new URL("http://www.paypal.com/cgi-bin/webscr");
256: URLConnection uc = u.openConnection();
257: uc.setDoOutput(true);
258: uc.setRequestProperty("Content-Type",
259: "application/x-www-form-urlencoded");
260: PrintWriter pw = new PrintWriter(uc.getOutputStream());
261: pw.println(str);
262: pw.close();
263:
264: BufferedReader in = new BufferedReader(
265: new InputStreamReader(uc.getInputStream()));
266: confirmResp = in.readLine();
267: in.close();
268: Debug.logError("PayPal Verification Response: "
269: + confirmResp, module);
270: } catch (IOException e) {
271: Debug.logError(e, "Problems sending verification message",
272: module);
273: }
274:
275: if (confirmResp.trim().equals("VERIFIED")) {
276: // we passed verification
277: Debug.logInfo("Got verification from PayPal, processing..",
278: module);
279: } else {
280: Debug
281: .logError(
282: "###### PayPal did not verify this request, need investigation!",
283: module);
284: Set keySet = parametersMap.keySet();
285: Iterator i = keySet.iterator();
286: while (i.hasNext()) {
287: String name = (String) i.next();
288: String value = request.getParameter(name);
289: Debug.logError("### Param: " + name + " => " + value,
290: module);
291: }
292: }
293:
294: // get the user
295: GenericValue userLogin = null;
296: String userLoginId = request.getParameter("custom");
297: if (userLoginId == null)
298: userLoginId = "admin";
299: try {
300: userLogin = delegator.findByPrimaryKey("UserLogin",
301: UtilMisc.toMap("userLoginId", userLoginId));
302: } catch (GenericEntityException e) {
303: Debug.logError(e, "Cannot get UserLogin for: "
304: + userLoginId + "; cannot continue", module);
305: request.setAttribute("_ERROR_MESSAGE_",
306: "<li>Problems getting authentication user.");
307: return "error";
308: }
309:
310: // get the orderId
311: String orderId = request.getParameter("invoice");
312:
313: // get the order header
314: GenericValue orderHeader = null;
315: try {
316: orderHeader = delegator.findByPrimaryKey("OrderHeader",
317: UtilMisc.toMap("orderId", orderId));
318: } catch (GenericEntityException e) {
319: Debug.logError(e, "Cannot get the order header for order: "
320: + orderId, module);
321: request.setAttribute("_ERROR_MESSAGE_",
322: "<li>Problems getting order header.");
323: return "error";
324: }
325:
326: // get payment data
327: String paymentCurrency = request.getParameter("mc_currency");
328: String paymentAmount = request.getParameter("mc_gross");
329: String paymentFee = request.getParameter("mc_fee");
330: String transactionId = request.getParameter("txn_id");
331:
332: // get the transaction status
333: String paymentStatus = request.getParameter("payment_status");
334:
335: // attempt to start a transaction
336: boolean beganTransaction = false;
337: try {
338: beganTransaction = TransactionUtil.begin();
339: } catch (GenericTransactionException gte) {
340: Debug.logError(gte, "Unable to begin transaction", module);
341: }
342:
343: boolean okay = false;
344: if (paymentStatus.equals("Completed")) {
345: okay = OrderChangeHelper.approveOrder(dispatcher,
346: userLogin, orderId);
347: } else if (paymentStatus.equals("Failed")
348: || paymentStatus.equals("Denied")) {
349: okay = OrderChangeHelper.cancelOrder(dispatcher, userLogin,
350: orderId);
351: }
352:
353: if (okay) {
354: // set the payment preference
355: okay = setPaymentPreferences(delegator, orderId, request);
356: }
357:
358: if (okay) {
359: try {
360: TransactionUtil.commit(beganTransaction);
361: } catch (GenericTransactionException gte) {
362: Debug.logError(gte, "Unable to commit transaction",
363: module);
364: }
365: } else {
366: try {
367: TransactionUtil.rollback(beganTransaction);
368: } catch (GenericTransactionException gte) {
369: Debug.logError(gte, "Unable to rollback transaction",
370: module);
371: }
372: }
373:
374: if (okay) {
375: // attempt to release the offline hold on the order (workflow)
376: OrderChangeHelper.releaseInitialOrderHold(dispatcher,
377: orderId);
378:
379: // call the email confirm service
380: Map emailContext = UtilMisc.toMap("orderId", orderId);
381: try {
382: Map emailResult = dispatcher.runSync(
383: "sendOrderConfirmation", emailContext);
384: } catch (GenericServiceException e) {
385: Debug.logError(e,
386: "Problems sending email confirmation", module);
387: }
388: }
389:
390: return "success";
391: }
392:
393: /** Event called when customer cancels a paypal order */
394: public static String cancelPayPalOrder(HttpServletRequest request,
395: HttpServletResponse response) {
396: ServletContext application = ((ServletContext) request
397: .getAttribute("servletContext"));
398: GenericDelegator delegator = (GenericDelegator) request
399: .getAttribute("delegator");
400: LocalDispatcher dispatcher = (LocalDispatcher) request
401: .getAttribute("dispatcher");
402: GenericValue userLogin = (GenericValue) request.getSession()
403: .getAttribute("userLogin");
404:
405: // get the stored order id from the session
406: String orderId = (String) request.getSession().getAttribute(
407: "PAYPAL_ORDER");
408:
409: // attempt to start a transaction
410: boolean beganTransaction = false;
411: try {
412: beganTransaction = TransactionUtil.begin();
413: } catch (GenericTransactionException gte) {
414: Debug.logError(gte, "Unable to begin transaction", module);
415: }
416:
417: // cancel the order
418: boolean okay = OrderChangeHelper.cancelOrder(dispatcher,
419: userLogin, orderId);
420:
421: if (okay) {
422: try {
423: TransactionUtil.commit(beganTransaction);
424: } catch (GenericTransactionException gte) {
425: Debug.logError(gte, "Unable to commit transaction",
426: module);
427: }
428: } else {
429: try {
430: TransactionUtil.rollback(beganTransaction);
431: } catch (GenericTransactionException gte) {
432: Debug.logError(gte, "Unable to rollback transaction",
433: module);
434: }
435: }
436:
437: // attempt to release the offline hold on the order (workflow)
438: if (okay)
439: OrderChangeHelper.releaseInitialOrderHold(dispatcher,
440: orderId);
441:
442: request.setAttribute("_EVENT_MESSAGE_",
443: "<li>Previous PayPal order has been cancelled.");
444: return "success";
445: }
446:
447: private static boolean setPaymentPreferences(
448: GenericDelegator delegator, String orderId,
449: ServletRequest request) {
450: Debug.logVerbose("Setting payment prefrences..", module);
451: List paymentPrefs = null;
452: try {
453: Map paymentFields = UtilMisc.toMap("orderId", orderId,
454: "statusId", "PAYMENT_NOT_RECEIVED");
455: paymentPrefs = delegator.findByAnd(
456: "OrderPaymentPreference", paymentFields);
457: } catch (GenericEntityException e) {
458: Debug.logError(e,
459: "Cannot get payment preferences for order #"
460: + orderId, module);
461: return false;
462: }
463: if (paymentPrefs != null && paymentPrefs.size() > 0) {
464: Iterator i = paymentPrefs.iterator();
465: while (i.hasNext()) {
466: GenericValue pref = (GenericValue) i.next();
467: boolean okay = setPaymentPreference(pref, request);
468: if (!okay)
469: return false;
470: }
471: }
472: return true;
473: }
474:
475: private static boolean setPaymentPreference(
476: GenericValue paymentPreference, ServletRequest request) {
477: String paymentDate = request.getParameter("payment_date");
478: String paymentType = request.getParameter("payment_type");
479: String paymentAmount = request.getParameter("mc_gross");
480: String paymentStatus = request.getParameter("payment_status");
481: String transactionId = request.getParameter("txn_id");
482:
483: List toStore = new LinkedList();
484:
485: // PayPal returns the timestamp in the format 'hh:mm:ss Jan 1, 2000 PST'
486: // Parse this into a valid Timestamp Object
487: SimpleDateFormat sdf = new SimpleDateFormat(
488: "hh:mm:ss MMM d, yyyy z");
489: java.sql.Timestamp authDate = null;
490: try {
491: authDate = new java.sql.Timestamp(sdf.parse(paymentDate)
492: .getTime());
493: } catch (ParseException e) {
494: Debug.logError(e, "Cannot parse date string: "
495: + paymentDate, module);
496: authDate = UtilDateTime.nowTimestamp();
497: } catch (NullPointerException e) {
498: Debug.logError(e, "Cannot parse date string: "
499: + paymentDate, module);
500: authDate = UtilDateTime.nowTimestamp();
501: }
502:
503: if (paymentStatus.equals("Completed")) {
504: paymentPreference.set("statusId", "PAYMENT_RECEIVED");
505: } else {
506: paymentPreference.set("statusId", "PAYMENT_CANCELLED");
507: }
508: toStore.add(paymentPreference);
509:
510: GenericDelegator delegator = paymentPreference.getDelegator();
511:
512: // create the PaymentGatewayResponse
513: String responseId = delegator.getNextSeqId(
514: "PaymentGatewayResponse").toString();
515: GenericValue response = delegator.makeValue(
516: "PaymentGatewayResponse", null);
517: response.set("paymentGatewayResponseId", responseId);
518: response.set("paymentServiceTypeEnumId", "PRDS_PAY_EXTERNAL");
519: response.set("orderPaymentPreferenceId", paymentPreference
520: .get("orderPaymentPreferenceId"));
521: response.set("paymentMethodTypeId", paymentPreference
522: .get("paymentMethodTypeId"));
523: response.set("paymentMethodId", paymentPreference
524: .get("paymentMethodId"));
525:
526: // set the auth info
527: response.set("amount", new Double(paymentAmount));
528: response.set("referenceNum", transactionId);
529: response.set("gatewayCode", paymentStatus);
530: response.set("gatewayFlag", paymentStatus.substring(0, 1));
531: response.set("gatewayMessage", paymentType);
532: response.set("transactionDate", authDate);
533: toStore.add(response);
534:
535: // create a payment record too
536: GenericValue payment = OrderChangeHelper
537: .createPaymentFromPreference(paymentPreference, null,
538: null, "Payment receive via PayPal");
539: toStore.add(payment);
540:
541: try {
542: delegator.storeAll(toStore);
543: } catch (GenericEntityException e) {
544: Debug.logError(e,
545: "Cannot set payment preference/payment info",
546: module);
547: return false;
548: }
549: return true;
550: }
551:
552: }
|