/*
* 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
}
}