/* * Copyright (C) 2010 Pete Reisinger <p.reisinger@gmail.com>. * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program. If * not, see <http://www.gnu.org/licenses/>. */ package paypalnvp.request; import paypalnvp.fields.*; import paypalnvp.util.Validator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Instance is used for SetExpressCheckout request. This request initiates an Express Checkout * transaction. * * @author Pete Reisinger * <p.reisinger@gmail.com> * . */ @SuppressWarnings("serial") public final class SetExpressCheckout implements Request { /** * Method value of this request */ private static final String METHOD_NAME = "SetExpressCheckout"; /** * name value pair request */ private final Map<String, String> nvpRequest; /** * name value pair response */ private Map<String, String> nvpResponse; /** * shipping options, empty if no options set */ private List<Map<String, String>> shippingOptions; /** * billing agreement (recurring payment etc.), empty if no agreemnt set */ private List<Map<String, String>> billingAgreement; /** * PayPal recommends that the returnUrl be the final review page on which the customer confirms * the order and payment or billing agreement. * <p/> * PayPal recommends that the cancelUrl be the original page on which the customer chose to pay * with PayPal or establish a billing agreement. * * @param payment * @param returnUrl URL to which the customer’s browser is returned after choosing to pay with * PayPal. Maximum 2048 characters. * @param cancelUrl URL to which the customer is returned if he does not approve the use of PayPal * to pay you. Maximum 2048 characters. * @throws IllegalArgumentException */ public SetExpressCheckout(Payment payment, String returnUrl, String cancelUrl) throws IllegalArgumentException { /* cancel url and return url has to be less or equal to 2048 chars */ if (returnUrl.length() >= 2048) { throw new IllegalArgumentException("returnUrl cannot be longer " + "than 2048 characters."); } if (cancelUrl.length() >= 2048) { throw new IllegalArgumentException("cancelUrl cannot be longer " + "than 2048 characters."); } if (payment == null || returnUrl == null || cancelUrl == null) { throw new IllegalArgumentException("Arguments cannot be null"); } nvpResponse = new HashMap<String, String>(); nvpRequest = new HashMap<String, String>(); shippingOptions = new LinkedList<Map<String, String>>(); billingAgreement = new LinkedList<Map<String, String>>(); nvpRequest.put("METHOD", METHOD_NAME); /* copy nvp from payment */ HashMap<String, String> nvp = new HashMap<String, String>(payment.getNVPRequest()); nvpRequest.putAll(nvp); nvpRequest.put("RETURNURL", returnUrl); nvpRequest.put("CANCELURL", cancelUrl); } /** * @param token A timestamp token * @throws IllegalArgumentException */ public void setToken(String token) throws IllegalArgumentException { if (token.length() != 20) { throw new IllegalArgumentException("Invalid token argument"); } nvpRequest.put("TOKEN", token); } /** * The expected maximum total amount of the complete order, including shipping cost and tax * charges. If the transaction does not include a one-time purchase, this field is ignored. * Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Must have two * decimal places, decimal separator must be a period (.), and no thousands separator. * * @param maxAmount number with exactly two decimal places * @throws IllegalArgumentException */ public void setMaxAmount(String maxAmount) throws IllegalArgumentException { /* amount is number with exactly two decimal places */ if (!Validator.isValidAmount(maxAmount)) { throw new IllegalArgumentException("Amount " + maxAmount + " is not valid. Amount has to have exactly two decimal " + "places seaprated by \".\" - example: \"50.00\""); } /* values for this request */ nvpRequest.put("MAXAMT", maxAmount); } /** * URL to which the callback request from PayPal is sent. It must start with HTTPS for production * integration. It can start with HTTPS or HTTP for sandbox testing. * * @param callback max 1024 characters */ public void setCallback(String callback) throws IllegalArgumentException { if (callback.length() > 1024) { throw new IllegalArgumentException("Callback can be maximum 1024 " + "in length"); } nvpRequest.put("CALLBACK", callback); } /** * An override for you to request more or less time to be able to process the callback request and * respond. The acceptable range for the override is 1 to 6 seconds. * * @param timeout integer has to be between 1 - 6 */ public void setCallbackTimeout(int timeout) { if (timeout < 1 || timeout > 6) { throw new IllegalArgumentException("Timeout has to be between 1 - 6"); } nvpRequest.put("CALLBACKTIMEOUT", Integer.toString(timeout)); } /** * Indicates that you require that the customer’s shipping address on file with PayPal be a * confirmed address. Setting this field overrides the setting you have specified in your Merchant * Account Profile. * * @param required if true than confirmed address is required */ public void setRequireConfirmedShipping(boolean required) { String req = (required) ? "1" : "0"; nvpRequest.put("REQCONFIRMSHIPPING", req); } /** * Indicates that on the PayPal pages, no shipping address fields should be displayed whatsoever. * * @param noShipping if true, no address fields will be displayed */ public void setNoShipping(boolean noShipping) { String no = (noShipping) ? "1" : "0"; nvpRequest.put("NOSHIPPING", no); } /** * Indicates that the customer may enter a note to the merchant on the PayPal page during * checkout. The note is returned in the GetExpressCheckoutDetails response and the * DoExpressCheckoutPayment response. * * @param allowNote if true, note can be entered by customer */ public void setAllowNote(boolean allowNote) { String note = (allowNote) ? "1" : "0"; nvpRequest.put("ALLOWNOTE", note); } /** * Indicates that the PayPal pages should display the shipping address set by you in this * SetExpressCheckout request, not the shipping address on file with PayPal for this customer. * Displaying the PayPal street address on file does not allow the customer to edit that address. * Set address using setAddress(ShipToAddress address) method * * @param rOverride if true set address will be used */ public void setAddressOverride(boolean rOverride) { String over = (rOverride) ? "1" : "0"; nvpRequest.put("ADDROVERRIDE", over); } /** * Locale of pages displayed by PayPal during Express Checkout. * * @param localCode */ public void setLocalCode(LocalCode localCode) { nvpRequest.put("LOCALECODE", localCode.toString()); } /** * Sets the Custom Payment Page Style for payment pages associated with this button/link. This * value corresponds to the HTML variable page_style for customizing payment pages. The value is * the same as the Page Style Name you chose when adding or editing the page style from the * Profile subtab of the My Account tab of your PayPal account. * <p/> * Character length and limitations: 30 single-byte alphabetic characters * * @param pageStyle * @throws IllegalArgumentException */ public void setPageStyle(String pageStyle) throws IllegalArgumentException { if (pageStyle.length() > 30) { throw new IllegalArgumentException("Character length exceeded 30 " + "characters"); } nvpRequest.put("PAGESTYLE", pageStyle); } /** * URL for the image you want to appear at the top left of the payment page. The image has a * maximum size of 750 pixels wide by 90 pixels high. PayPal recommends that you provide an image * that is stored on a secure (https) server. If you do not specify an image, the business name is * displayed. Character length and limit: 127 single-byte alphanumeric characters * * @param imgUrl * @throws IllegalArgumentException */ public void setImage(String imgUrl) throws IllegalArgumentException { if (imgUrl.length() > 127) { throw new IllegalArgumentException("Character length exceeded 30 " + "characters"); } nvpRequest.put("HDRIMG", imgUrl); } /** * Sets the border color around the header of the payment page. The border is a 2-pixel perimeter * around the header space, which is 750 pixels wide by 90 pixels high. By default, the color is * black. Character length and limitation: Six character HTML hexadecimal color code in ASCII * * @param hexColor * @throws IllegalArgumentException */ public void setBorderColor(String hexColor) throws IllegalArgumentException { /* allowed characters 0-9 and a-f. Exactly 6 characters */ Pattern pattern = Pattern.compile("^[0-9,a-f,A-F]{6}$"); Matcher matcher = pattern.matcher(hexColor); if (!matcher.find()) { throw new IllegalArgumentException("Hex color" + hexColor + " is not valid."); } nvpRequest.put("HDRBORDERCOLOR", hexColor); } /** * Sets the background color for the header of the payment page. By default, the color is white. * Character length and limitation: Six character HTML hexadecimal color code in ASCII * * @param hexColor * @throws IllegalArgumentException */ public void setBackgroundColor(String hexColor) throws IllegalArgumentException { /* allowed characters 0-9 and a-f. Exactly 6 characters */ Pattern pattern = Pattern.compile("^[0-9,a-f,A-F]{6}$"); Matcher matcher = pattern.matcher(hexColor); if (!matcher.find()) { throw new IllegalArgumentException("Hex color" + hexColor + " is not valid."); } nvpRequest.put("HDRBACKCOLOR", hexColor); } /** * Sets the background color for the payment page. By default, the color is white. Character * length and limitation: Six character HTML hexadecimal color code in ASCII * * @param hexColor * @throws IllegalArgumentException */ public void setPayFlowColor(String hexColor) throws IllegalArgumentException { /* allowed characters 0-9 and a-f. Exactly 6 characters */ Pattern pattern = Pattern.compile("^[0-9,a-f,A-F]{6}$"); Matcher matcher = pattern.matcher(hexColor); if (!matcher.find()) { throw new IllegalArgumentException("Hex color" + hexColor + " is not valid."); } nvpRequest.put("PAYFLOWCOLOR", hexColor); } /** * How you want to obtain payment: * <ul> * <li> * Sale indicates that this is a final sale for which you are requesting payment. (Default)</li> * <li> * Authorization indicates that this payment is a basic authorization subject to settlement with * PayPal Authorization & Capture.</li> * <li> * Order indicates that this payment is an order authorization subject to settlement with PayPal * Authorization & Capture.</li> * </ul> * If the transaction does not include a one-time purchase, this field is ignored. Note: You * cannot set this value to Sale in SetExpressCheckout request and then change this value to * Authorization or Order on the final API DoExpressCheckoutPayment request. If the value is set * to Authorization or Order in SetExpressCheckout, the value may be set to Sale or the same value * (either Authorization or Order) in DoExpressCheckoutPayment. * * @param paymentAction */ public void setPaymentAction(PaymentAction paymentAction) { nvpRequest.put("PAYMENTACTION", paymentAction.getValue()); } /** * Email address of the buyer as entered during checkout. PayPal uses this value to pre-fill the * PayPal membership sign-up portion of the PayPal login page. Character length and limit: 127 * single-byte alphanumeric characters * * @param email * @throws IllegalArgumentException */ public void setEmail(String email) throws IllegalArgumentException { if (!Validator.isValidEmail(email)) { throw new IllegalArgumentException("Email is not valid"); } if (email.length() > 127) { throw new IllegalArgumentException("Email can be maximum 127 " + "characters long."); } nvpRequest.put("EMAIL", email); } /** * Type of checkout flow: * <ul> * <li><b>Sole:</b> Express Checkout for auctions</li> * <li><b>Mark:</b> Normal Express Checkout</li> * </ul> * * @param solutionType */ public void setSolutionType(SolutionType solutionType) { nvpRequest.put("SOLUTIONTYPE", solutionType.toString()); } /** * Type of PayPal page to display: * <ul> * <li><b>Billing:</b> non-PayPal account</li> * <li><b>Login:</b> PayPal account login</li> * </ul> * * @param landingPage */ public void setLandingPage(LandingPage landingPage) { nvpRequest.put("LANDINGPAGE", landingPage.toString()); } /** * Type of channel: * <ul> * <li><b>Merchant:</b> non-auction seller</li> * <li><b>eBayItem:</b> eBay auction</li> * </ul> * * @param channelType */ public void setChannelType(ChannelType channelType) { nvpRequest.put("CHANNELTYPE", channelType.toString()); } /** * The URL on the merchant site to redirect to after a successful giropay payment. Use this field * only if you are using giropay or bank transfer payment methods in Germany. * * @param url */ public void setGiroPaySuccessUrl(String url) { nvpRequest.put("GIROPAYSUCCESSURL", url); } /** * The URL on the merchant site to redirect to after a unsuccessful giropay payment. Use this * field only if you are using giropay or bank transfer payment methods in Germany. * * @param url */ public void setGiroCancelUrl(String url) { nvpRequest.put("GIROPAYCANCELURL", url); } /** * The URL on the merchant site to transfer to after a bank transfer payment. Use this field only * if you are using giropay or bank transfer payment methods in Germany. * * @param url */ public void setBankTxPendingUrl(String url) { nvpRequest.put("BANKTXNPENDINGURL", url); } /** * Sets address fields * * @param address */ public void setAddress(Address address) { nvpRequest.putAll(address.getNVPRequest()); } /** * Sets shipping options * * @param options */ public void setShippingOptions(ShippingOptions[] options) { /* check items */ if (options == null || options.length == 0) { throw new IllegalArgumentException("You did not supply options."); } /* iterate supplied array */ int x = 0; // this is only for exception message for (ShippingOptions option : options) { /* item cannot be null */ if (option == null) { throw new IllegalArgumentException("Option at index " + x + " is not set."); } this.shippingOptions.add(new HashMap<String, String>(option.getNVPRequest())); x++; } } /** * Sets billing agreement (recurring payments etc.). Maximum allowed billing agreements is 10 * * @param agreements */ public void setBillingAgreement(BillingAgreement[] agreements) { /* check items */ if (agreements == null || agreements.length == 0) { throw new IllegalArgumentException("You did not supply any agreement."); } if (agreements.length > 10) { throw new IllegalArgumentException("Maximum allowed agreements is 10"); } /* iterate supplied array */ int x = 0; // this is only for exception message for (BillingAgreement agreement : agreements) { /* item cannot be null */ if (agreement == null) { throw new IllegalArgumentException("Agreement at index " + x + " is not set."); } this.billingAgreement.add(new HashMap<String, String>(agreement.getNVPRequest())); x++; } } /** * Sets buyer details * * @param buyer */ public void setBuyerDetails(BuyerDetails buyer) { nvpRequest.putAll(new HashMap<String, String>(buyer.getNVPRequest())); } /** * @param address shipping address */ public void setShippingAddress(ShipToAddress address) { nvpRequest.putAll(new HashMap<String, String>(address.getNVPRequest())); } public Map<String, String> getNVPRequest() { /* hash map holding response */ HashMap<String, String> nvp = new HashMap<String, String>(nvpRequest); /* shipping options */ for (int i = 0; i < shippingOptions.size(); i++) { for (Map.Entry<String, String> entry : shippingOptions.get(i).entrySet()) { /* KEYn VALUE */ nvp.put(entry.getKey() + i, entry.getValue()); } } /* billing agreement */ for (int i = 0; i < billingAgreement.size(); i++) { for (Map.Entry<String, String> entry : billingAgreement.get(i).entrySet()) { /* KEYn VALUE */ nvp.put(entry.getKey() + i, entry.getValue()); } } return nvp; } public Map<String, String> getNVPResponse() { return new HashMap<String, String>(nvpResponse); } public void setNVPResponse(Map<String, String> nvpResponse) { this.nvpResponse = new HashMap<String, String>(nvpResponse); } @Override public String toString() { StringBuffer str = new StringBuffer("instance of SetExpressCheckout "); str.append("class with the vlues: nvpRequest - "); str.append(nvpRequest.toString()); str.append("; nvpResponse - "); str.append(nvpResponse.toString()); return str.toString(); } /** * Locale of pages displayed by PayPal during Express Checkout. */ public enum LocalCode { /** * Australia */ AU, /** * Austria */ AT, /** * Belgium */ BE, /** * Canada */ CA, /** * Switzerland */ CH, /** * China */ CN, /** * Germany */ DE, /** * Spain */ ES, /** * United Kingdom */ GB, /** * France */ FR, /** * Italy */ IT, /** * Netherlands */ NL, /** * Poland */ PL, /** * United States */ US; } /** * Type of checkout flow */ public enum SolutionType { /** * Express Checkout for auctions */ SOLE, /** * Normal Express Checkout */ MARK } /** * Type of PayPal page to display */ public enum LandingPage { /** * non-PayPal account */ BILLING, /** * PayPal account login */ LOGIN } /** * Type of channel */ public enum ChannelType { /** * non-auction seller */ MERCHANT, /** * eBay auction */ EBAYITEM } }