/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Copyright (c) frentix GmbH<br> * http://www.frentix.com<br> * <p> */ package org.olat.resource.accesscontrol.provider.paypal.manager; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.UUID; import javax.persistence.TypedQuery; import org.olat.core.commons.persistence.DB; import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.resource.OLATResource; import org.olat.resource.accesscontrol.ACService; import org.olat.resource.accesscontrol.AccessTransaction; import org.olat.resource.accesscontrol.Offer; import org.olat.resource.accesscontrol.OfferAccess; import org.olat.resource.accesscontrol.Order; import org.olat.resource.accesscontrol.OrderLine; import org.olat.resource.accesscontrol.OrderPart; import org.olat.resource.accesscontrol.OrderStatus; import org.olat.resource.accesscontrol.Price; import org.olat.resource.accesscontrol.ResourceReservation; import org.olat.resource.accesscontrol.manager.ACOrderDAO; import org.olat.resource.accesscontrol.manager.ACReservationDAO; import org.olat.resource.accesscontrol.manager.ACTransactionDAO; import org.olat.resource.accesscontrol.model.AccessMethod; import org.olat.resource.accesscontrol.model.AccessTransactionStatus; import org.olat.resource.accesscontrol.model.PSPTransaction; import org.olat.resource.accesscontrol.provider.paypal.PaypalModule; import org.olat.resource.accesscontrol.provider.paypal.model.PaypalAccessMethod; import org.olat.resource.accesscontrol.provider.paypal.model.PaypalTransaction; import org.olat.resource.accesscontrol.provider.paypal.model.PaypalTransactionStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.paypal.exception.ClientActionRequiredException; import com.paypal.exception.HttpErrorException; import com.paypal.exception.InvalidCredentialException; import com.paypal.exception.InvalidResponseDataException; import com.paypal.exception.MissingCredentialException; import com.paypal.exception.SSLConfigurationException; import com.paypal.sdk.exceptions.OAuthException; import com.paypal.svcs.services.AdaptivePaymentsService; import com.paypal.svcs.types.ap.ConvertCurrencyRequest; import com.paypal.svcs.types.ap.ConvertCurrencyResponse; import com.paypal.svcs.types.ap.CurrencyCodeList; import com.paypal.svcs.types.ap.CurrencyConversionList; import com.paypal.svcs.types.ap.CurrencyList; import com.paypal.svcs.types.ap.PayRequest; import com.paypal.svcs.types.ap.PayResponse; import com.paypal.svcs.types.ap.PaymentDetailsRequest; import com.paypal.svcs.types.ap.PaymentDetailsResponse; import com.paypal.svcs.types.ap.Receiver; import com.paypal.svcs.types.ap.ReceiverList; import com.paypal.svcs.types.common.AckCode; import com.paypal.svcs.types.common.ClientDetailsType; import com.paypal.svcs.types.common.CurrencyType; import com.paypal.svcs.types.common.DetailLevelCode; import com.paypal.svcs.types.common.RequestEnvelope; import com.paypal.svcs.types.common.ResponseEnvelope; /** * * Description:<br> * * <P> * Initial Date: 23 mai 2011 <br> * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Service("paypalManager") public class PaypalManagerImpl implements PaypalManager { private static final OLog log = Tracing.createLoggerFor(PaypalManagerImpl.class); private static final String X_PAYPAL_SECURITY_USERID = "acct1.UserName"; private static final String X_PAYPAL_SECURITY_PASSWORD = "acct1.Password"; private static final String X_PAYPAL_SECURITY_SIGNATURE = "acct1.Signature"; private static final String X_PAYPAL_APPLICATION_ID = "acct1.AppId"; private static final String X_PAYPAL_SANDBOX_EMAIL_ADDRESS = "sandbox.EmailAddress"; private static final String X_PAYPAL_DEVICE_IPADDRESS = "X-PAYPAL-DEVICE-IPADDRESS"; private static final String API_BASE_ENDPOINT = "service.EndPoint.AdaptivePayments"; private static final String USE_PROXY = "http.UseProxy"; private static final String PROXY_HOST = "http.ProxyHost"; private static final String PROXY_PORT = "http.ProxyPort"; private static final String SANDBOX_API_BASE_ENDPOINT = "https://svcs.sandbox.paypal.com"; private static final String LIFE_API_BASE_ENDPOINT = "https://svcs.paypal.com"; @Autowired private DB dbInstance; @Autowired private ACOrderDAO orderManager; @Autowired private ACService acService; @Autowired private ACTransactionDAO transactionManager; @Autowired private PaypalModule paypalModule; @Autowired private ACReservationDAO reservationDao; private Properties getAccountProperties() { boolean sandboxed = paypalModule.isSandbox(); Properties accountProps = new Properties(); accountProps.setProperty(X_PAYPAL_SECURITY_USERID, paypalModule.getPaypalSecurityUserId()); accountProps.setProperty(X_PAYPAL_SECURITY_PASSWORD, paypalModule.getPaypalSecurityPassword()); accountProps.setProperty(X_PAYPAL_SECURITY_SIGNATURE, paypalModule.getPaypalSecuritySignature()); accountProps.setProperty(X_PAYPAL_APPLICATION_ID, paypalModule.getPaypalApplicationId()); try { accountProps.setProperty(X_PAYPAL_DEVICE_IPADDRESS, paypalModule.getDeviceIpAddress()); } catch (Exception e) { log.error("Cannot resolve the ip address from the server domain name", e); } if(sandboxed) { accountProps.setProperty(X_PAYPAL_SANDBOX_EMAIL_ADDRESS, paypalModule.getPaypalSandboxEmailAddress()); accountProps.setProperty(API_BASE_ENDPOINT, SANDBOX_API_BASE_ENDPOINT); } else { accountProps.setProperty(API_BASE_ENDPOINT, LIFE_API_BASE_ENDPOINT); } accountProps.setProperty(USE_PROXY, paypalModule.isUseProxy() ? "TRUE" : "FALSE"); accountProps.setProperty(PROXY_HOST, ""); accountProps.setProperty(PROXY_PORT, "8080"); return accountProps; } private ClientDetailsType getAppDetails() { ClientDetailsType cl = new ClientDetailsType(); cl.setDeviceId(Settings.getNodeInfo()); cl.setIpAddress("127.0.0.1"); cl.setApplicationId(paypalModule.getPaypalApplicationId()); return cl; } private RequestEnvelope getAppRequestEnvelope() { RequestEnvelope en = new RequestEnvelope(); en.setDetailLevel(DetailLevelCode.RETURNALL); en.setErrorLanguage("en"); return en; } private void save(PaypalAccessMethod accessMethod) { if(accessMethod.getKey() == null) { dbInstance.saveObject(accessMethod); } else { dbInstance.updateObject(accessMethod); } } private PaypalAccessMethod getMethodSecure(Long key) { PaypalAccessMethod smethod = null; List<PaypalAccessMethod> methods = getPaypalMethods(); if(methods.size() > 0) { smethod = methods.get(0); } else { smethod = new PaypalAccessMethod(); smethod.setCreationDate(new Date()); smethod.setLastModified(smethod.getCreationDate()); save(smethod); } for(PaypalAccessMethod method:methods) { if(key != null && key.equals(method.getKey())) { smethod = method; } } return smethod; } private List<PaypalAccessMethod> getPaypalMethods() { StringBuilder sb = new StringBuilder(); sb.append("select method from ").append(PaypalAccessMethod.class.getName()).append(" method"); List<PaypalAccessMethod> methods = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), PaypalAccessMethod.class) .getResultList(); return methods; } @Override public PaypalTransaction loadTransactionByUUID(String uuid) { StringBuilder sb = new StringBuilder(); sb.append("select trx from ").append(PaypalTransaction.class.getName()).append(" as trx where "); sb.append("(trx.secureCancelUUID=:uuid or trx.secureSuccessUUID=:uuid)"); TypedQuery<PaypalTransaction> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), PaypalTransaction.class); if(StringHelper.containsNonWhitespace(uuid)) { query.setParameter("uuid", uuid); } List<PaypalTransaction> transactions = query.getResultList(); if(transactions.isEmpty()) return null; return transactions.get(0); } public PaypalTransaction loadTransactionByInvoiceId(String invoiceId) { StringBuilder sb = new StringBuilder(); sb.append("select trx from ").append(PaypalTransaction.class.getName()).append(" as trx where "); sb.append("trx.refNo=:invoiceId"); List<PaypalTransaction> transactions = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), PaypalTransaction.class) .setParameter("invoiceId", invoiceId) .getResultList(); if(transactions.isEmpty()) return null; return transactions.get(0); } @Override public PaypalTransaction loadTransaction(Order order, OrderPart part) { StringBuilder sb = new StringBuilder(); sb.append("select trx from ").append(PaypalTransaction.class.getName()).append(" as trx where "); sb.append("(trx.orderId=:orderId and trx.orderPartId=:orderPartId)"); List<PaypalTransaction> transactions = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), PaypalTransaction.class) .setParameter("orderId", order.getKey()) .setParameter("orderPartId", part.getKey()) .getResultList(); if(transactions.isEmpty()) return null; return transactions.get(0); } @Override public List<PSPTransaction> loadTransactions(List<Order> orders) { if(orders == null || orders.isEmpty()) return Collections.emptyList(); StringBuilder sb = new StringBuilder(); sb.append("select trx from ").append(PaypalTransaction.class.getName()).append(" as trx where "); sb.append("trx.orderId in (:orderIds)"); List<Long> orderIds = new ArrayList<Long>(orders.size()); for(Order order:orders) { orderIds.add(order.getKey()); } List<PSPTransaction> transactions = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), PSPTransaction.class) .setParameter("orderIds", orderIds) .getResultList(); return transactions; } @Override public List<PaypalTransaction> findTransactions(String transactionId) { StringBuilder sb = new StringBuilder(); sb.append("select trx from ").append(PaypalTransaction.class.getName()).append(" as trx "); boolean where = false; if(StringHelper.containsNonWhitespace(transactionId)) { where = appendAnd(sb, where); sb.append(" (trx.transactionId=:transactionId or trx.senderTransactionId=:transactionId or trx.refNo=:transactionId) "); } sb.append(" order by trx.payResponseDate asc"); TypedQuery<PaypalTransaction> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), PaypalTransaction.class); if(StringHelper.containsNonWhitespace(transactionId)) { query.setParameter("transactionId", transactionId); } List<PaypalTransaction> transactions = query.getResultList(); return transactions; } private boolean appendAnd(StringBuilder sb, boolean where) { if(where) sb.append(" and "); else sb.append(" where "); return true; } private void updateTransaction(PayResponse payResp, PaypalTransaction trx) { trx.setPayKey(payResp.getPayKey()); trx.setPaymentExecStatus(payResp.getPaymentExecStatus()); ResponseEnvelope resEnv = payResp.getResponseEnvelope(); AckCode ack = resEnv.getAck(); trx.setAck(ack == null ? null : ack.getValue()); trx.setBuild(resEnv.getBuild()); trx.setCoorelationId(resEnv.getCorrelationId()); trx.setPayResponseDate(new Date()); dbInstance.updateObject(trx); } @Override public void updateTransaction(String uuid) { PaypalTransaction trx = loadTransactionByUUID(uuid); if(uuid.equals(trx.getSecureSuccessUUID())) { log.audit("Paypal transaction success: " + trx); completeTransaction(trx, null); } else if (uuid.equals(trx.getSecureCancelUUID())) { //cancel -> return to the access panel log.audit("Paypal transaction canceled by user: " + trx); cancelTransaction(trx); } } @Override public void updateTransactionByNotification(Map<String,String> values, boolean verified) { if(verified) { //CREATED - The payment request was received; funds will be transferred //COMPLETED - The payment was successful //INCOMPLETE - Some transfers succeeded and some failed for a parallel payment or, for a delayed chained payment, secondary receivers have not been paid //ERROR - The payment failed and all attempted transfers failed or all //REVERSALERROR - One or more transfers failed when attempting to //PROCESSING - The payment is in progress //PENDING - The payment is awaiting processing //String status = values.get("status"); //if("COMPLETED".equals(status)) String invoiceId = values.get("transaction[0].invoiceId"); PaypalTransaction trx = loadTransactionByInvoiceId(invoiceId); if(trx != null) { completeTransaction(trx, values); } else { log.error("Paypal IPN Transaction not found: " + values, null); } } else { String invoiceId = values.get("transaction[0].invoiceId"); log.error("Paypal IPN Transaction not verified: " + invoiceId + " raw values: " + values, null); } } private synchronized void cancelTransaction(PaypalTransaction trx) { if(trx.getStatus() == PaypalTransactionStatus.SUCCESS || trx.getStatus() == PaypalTransactionStatus.CANCELED) { //already completed: if successed -> let it in this state return; } updateTransaction(trx, PaypalTransactionStatus.CANCELED); Order order = orderManager.loadOrderByNr(trx.getRefNo()); orderManager.save(order, OrderStatus.CANCELED); //cancel the reservations Identity identity = order.getDelivery(); for(OrderPart part:order.getParts()) { if(part.getKey().equals(trx.getOrderPartId())) { for(OrderLine line:part.getOrderLines()) { OLATResource resource = line.getOffer().getResource(); ResourceReservation reservation = acService.getReservation(identity, resource); if(reservation != null) { acService.removeReservation(identity, identity, reservation); log.audit("Remove reservation after cancellation for: " + reservation + " to " + identity, null); } } } } } /** * Success -> save order and authorize the access * Pending -> save order and authorize the access * Denied -> save order and revert authorization to the access * @param trx */ private synchronized void completeTransaction(PaypalTransaction trx, Map<String,String> values) { //access already authorized if(trx.getStatus() == PaypalTransactionStatus.SUCCESS || trx.getStatus() == PaypalTransactionStatus.PENDING) { if(appendInfos(trx, values)) { dbInstance.updateObject(trx); } //check if the status changes String trxStatus = trx.getTransactionStatus(); if(trxStatus.equalsIgnoreCase("DENIED")) { completeDeniedTransaction(trx); } else { return;//already completed } } appendInfos(trx, values); //SUCCESS – The sender’s transaction has completed //PENDING – The transaction is awaiting further processing //CREATED – The payment request was received; funds will be transferred //PARTIALLY_REFUNDED– Transaction was partially refunded //DENIED – The transaction was rejected by the receiver //PROCESSING – The transaction is in progress //REVERSED – The payment was returned to the sender //null, Success, Pending -> authorize String trxStatus = trx.getTransactionStatus(); if(trxStatus != null && "DENIED".equalsIgnoreCase(trxStatus)) { completeDeniedTransaction(trx); } else { completeTransactionSucessfully(trx, trxStatus); } } private void completeDeniedTransaction(PaypalTransaction trx) { updateTransaction(trx, PaypalTransactionStatus.DENIED); Order order = orderManager.loadOrderByNr(trx.getRefNo()); order = orderManager.save(order, OrderStatus.ERROR); PaypalAccessMethod method = getMethodSecure(trx.getMethodId()); if(order.getKey().equals(trx.getOrderId())) { //make accessible Identity identity = order.getDelivery(); for(OrderPart part:order.getParts()) { if(part.getKey().equals(trx.getOrderPartId())) { AccessTransaction transaction = transactionManager.createTransaction(order, part, method); transaction = transactionManager.update(transaction, AccessTransactionStatus.ERROR); for(OrderLine line:part.getOrderLines()) { acService.denyAccesToResource(identity, line.getOffer()); log.audit("Paypal payed access revoked for: " + buildLogMessage(line, method) + " to " + identity, null); ResourceReservation reservation = reservationDao.loadReservation(identity, line.getOffer().getResource()); if(reservation != null) { acService.removeReservation(identity, identity, reservation); log.audit("Remove reservation after cancellation for: " + reservation + " to " + identity, null); } } } } } else { log.error("Order not in sync with PaypalTransaction", null); } } private void completeTransactionSucessfully(PaypalTransaction trx, String trxStatus) { Order order = orderManager.loadOrderByNr(trx.getRefNo()); if("PENDING".equalsIgnoreCase(trxStatus)) { updateTransaction(trx, PaypalTransactionStatus.PENDING); } else { updateTransaction(trx, PaypalTransactionStatus.SUCCESS); } order = orderManager.save(order, OrderStatus.PAYED); PaypalAccessMethod method = getMethodSecure(trx.getMethodId()); if(order.getKey().equals(trx.getOrderId())) { //make accessible Identity identity = order.getDelivery(); for(OrderPart part:order.getParts()) { if(part.getKey().equals(trx.getOrderPartId())) { AccessTransaction transaction = transactionManager.createTransaction(order, part, method); transaction = transactionManager.save(transaction); for(OrderLine line:part.getOrderLines()) { if(acService.allowAccesToResource(identity, line.getOffer())) { log.audit("Paypal payed access granted for: " + buildLogMessage(line, method) + " to " + identity, null); transaction = transactionManager.update(transaction, AccessTransactionStatus.SUCCESS); } else { log.error("Paypal payed access refused for: " + buildLogMessage(line, method) + " to " + identity, null); transaction = transactionManager.update(transaction, AccessTransactionStatus.ERROR); } } } } } else { log.error("Order not in sync with PaypalTransaction", null); } } private String buildLogMessage(OrderLine line, PaypalAccessMethod method) { StringBuilder sb = new StringBuilder(); Offer offer = line.getOffer(); sb.append("OrderLine[key=").append(line.getKey()).append("]") .append("[method=").append(method.getClass().getSimpleName()).append("]"); if(offer == null) { sb.append("[resource=null]"); } else { sb.append("[resource=").append(offer.getResourceId()).append(":").append(offer.getResourceTypeName()).append(":").append(offer.getResourceDisplayName()).append("]"); } return sb.toString(); } private boolean appendInfos(PaypalTransaction trx, Map<String,String> values) { if(values == null) return false; boolean append = false; String senderTrxId = values.get("transaction[0].id_for_sender_txn"); if(StringHelper.containsNonWhitespace(senderTrxId)) { trx.setSenderTransactionId(senderTrxId); append = true; } String statusSenderTrx = values.get("transaction[0].status_for_sender_txn"); if(StringHelper.containsNonWhitespace(statusSenderTrx)) { trx.setSenderTransactionStatus(statusSenderTrx); append = true; } String receiverTrxId = values.get("transaction[0].id"); if(StringHelper.containsNonWhitespace(receiverTrxId)) { trx.setTransactionId(receiverTrxId); append = true; } String senderEmail = values.get("sender_email"); if(StringHelper.containsNonWhitespace(senderEmail)) { trx.setSenderEmail(senderEmail); append = true; } String verifySign = values.get("verify_sign"); if(StringHelper.containsNonWhitespace(verifySign)) { trx.setVerifySign(verifySign); append = true; } String pendingReason = values.get("transaction[0].pending_reason"); if(StringHelper.containsNonWhitespace(pendingReason)) { trx.setPendingReason(pendingReason); append = true; } String transactionStatus = values.get("transaction[0].status"); if(StringHelper.containsNonWhitespace(transactionStatus)) { trx.setTransactionStatus(transactionStatus); append = true; } return append; } @Override public void updateTransaction(PaypalTransaction transaction, PaypalTransactionStatus status) { transaction.setStatus(status); dbInstance.updateObject(transaction); } /* * @return */ private PaypalTransaction createAndPersistTransaction(Price amount, Order order, OrderPart part, AccessMethod method) { PaypalTransaction transaction = new PaypalTransaction(); transaction.setRefNo(order.getOrderNr()); transaction.setSecureSuccessUUID(UUID.randomUUID().toString().replace("-", "")); transaction.setSecureCancelUUID(UUID.randomUUID().toString().replace("-", "")); transaction.setStatus(PaypalTransactionStatus.NEW); transaction.setOrderId(order.getKey()); transaction.setOrderPartId(part.getKey()); transaction.setMethodId(method.getKey()); transaction.setSecurePrice(amount); dbInstance.saveObject(transaction); return transaction; } @Override public boolean convertCurrency() { try { String[] fromcodes = new String[]{"CHF"}; String[] tocodes = new String[]{"USD"}; BigDecimal[] amountItems = new BigDecimal[]{ new BigDecimal("20.00")}; CurrencyList list = new CurrencyList(); CurrencyCodeList cclist = new CurrencyCodeList(); for (int i = 0; i < amountItems.length; i++) { CurrencyType ct = new CurrencyType(); ct.setAmount(amountItems[i].doubleValue()); ct.setCode(fromcodes[i]); list.getCurrency().add(ct); } for (int i = 0; i < tocodes.length; i++) { cclist.getCurrencyCode().add(tocodes[i]); } ConvertCurrencyRequest req = new ConvertCurrencyRequest(); req.setBaseAmountList(list); req.setConvertToCurrencyList(cclist); req.setRequestEnvelope(getAppRequestEnvelope()); AdaptivePaymentsService ap = new AdaptivePaymentsService(getAccountProperties()); ConvertCurrencyResponse resp = ap.convertCurrency(req); for (Iterator<CurrencyConversionList> iterator = resp.getEstimatedAmountTable().getCurrencyConversionList().iterator(); iterator.hasNext();) { CurrencyConversionList ccclist = iterator.next(); log.info(ccclist.getBaseAmount().getCode() + " :: "+ ccclist.getBaseAmount().getAmount()); List<CurrencyType> l = ccclist.getCurrencyList().getCurrency(); for (int i = 0; i < l.size(); i++) { CurrencyType ct = l.get(i); log.info(ct.getCode() + " :: "+ ct.getAmount()); } } return true; } catch (SSLConfigurationException e) { log.error("Paypal error", e); return false; } catch (InvalidCredentialException e) { log.error("Paypal error", e); return false; } catch (UnsupportedEncodingException e) { log.error("Paypal error", e); return false; } catch (HttpErrorException e) { log.error("Paypal error", e); return false; } catch (InvalidResponseDataException e) { log.error("Paypal error", e); return false; } catch (ClientActionRequiredException e) { log.error("Paypal error", e); return false; } catch (MissingCredentialException e) { log.error("Paypal error", e); return false; } catch (OAuthException e) { log.error("Paypal error", e); return false; } catch (IOException | InterruptedException e) { log.error("Paypal error", e); return false; } catch (Exception e) { log.error("", e); return false; } } @Override public String getPayRedirectUrl(PayResponse response) { String testEnv = ""; if(paypalModule.isSandbox()) { testEnv = "sandbox."; } String payKey = response.getPayKey(); String nextUrl= "https://www." + testEnv + "paypal.com/cgi-bin/webscr?cmd=_ap-payment&paykey=" + payKey; return nextUrl; } @Override public String getIpnVerificationUrl() { String testEnv = ""; if(paypalModule.isSandbox()) { testEnv = "sandbox."; } String verificationUrl= "https://www." + testEnv + "paypal.com/cgi-bin/webscr"; return verificationUrl; } @Override public PaymentDetailsResponse paymentDetails(String key) { try { PaymentDetailsRequest paydetailReq = new PaymentDetailsRequest(); paydetailReq.setPayKey(key); paydetailReq.setRequestEnvelope(getAppRequestEnvelope()); AdaptivePaymentsService apd = new AdaptivePaymentsService(getAccountProperties()); PaymentDetailsResponse paydetailsResp = apd.paymentDetails(paydetailReq); return paydetailsResp; } catch (Exception fe) { log.error("", fe); return null; } } public PayResponse request(Identity delivery, OfferAccess offerAccess, String mapperUri, String sessionId) { StringBuilder url = new StringBuilder(); url.append(Settings.createServerURI()).append(mapperUri); Offer offer = offerAccess.getOffer(); Price amount = offer.getPrice(); Order order = orderManager.saveOneClick(delivery, offerAccess, OrderStatus.PREPAYMENT); PaypalTransaction trx = createAndPersistTransaction(amount, order, order.getParts().get(0), offerAccess.getMethod()); //!!!! make a trace of the process dbInstance.commit(); ReceiverList list = new ReceiverList(); Receiver rec1 = new Receiver(); rec1.setAmount(amount.getAmount().doubleValue()); rec1.setEmail(paypalModule.getPaypalFirstReceiverEmailAddress()); rec1.setInvoiceId(order.getOrderNr()); list.getReceiver().add(rec1); String returnURL = url.toString() + "/" + trx.getSecureSuccessUUID() + ".html;jsessionid=" + sessionId + "?status=success"; String cancelURL = url.toString() + "/" + trx.getSecureCancelUUID() + ".html;jsessionid=" + sessionId + "?status=cancel"; System.out.println(returnURL); PayRequest payRequest = new PayRequest(); payRequest.setCancelUrl(cancelURL); payRequest.setReturnUrl(returnURL); payRequest.setTrackingId(order.getOrderNr()); payRequest.setCurrencyCode(amount.getCurrencyCode()); payRequest.setClientDetails(getAppDetails()); payRequest.setReceiverList(list); payRequest.setRequestEnvelope(getAppRequestEnvelope()); payRequest.setActionType("PAY"); payRequest.setIpnNotificationUrl(Settings.getServerContextPathURI() + "/paypal/ipn"); PayResponse payResp = null; try { AdaptivePaymentsService ap = new AdaptivePaymentsService(getAccountProperties()); payResp = ap.pay(payRequest); log.audit("Paypal send PayRequest: " + (payResp == null ? "no response" : payResp.getPayKey() + "/" + payResp.getPaymentExecStatus())); return payResp; } catch (SSLConfigurationException e) { log.error("Paypal error", e); } catch (InvalidCredentialException e) { log.error("Paypal error", e); } catch (UnsupportedEncodingException e) { log.error("Paypal error", e); } catch (HttpErrorException e) { log.error("Paypal error", e); } catch (InvalidResponseDataException e) { log.error("Paypal error", e); } catch (ClientActionRequiredException e) { log.error("Paypal error", e); } catch (MissingCredentialException e) { log.error("Paypal error", e); } catch (OAuthException e) { log.error("Paypal error", e); } catch (IOException | InterruptedException e) { log.error("Paypal error", e); } catch (Exception e) { log.error("Paypal error", e); } finally { if(payResp == null) { updateTransaction(trx, PaypalTransactionStatus.ERROR); } else { updateTransaction(payResp, trx); } } return null; } }