#!/usr/bin/env bash :<<'__comments__' Name: set-express-checkout Usage: See show_usage() Synopsis: Configure and request a buyer checkout session in the PayPal sandbox, accept a reply token and compose an URL to test Express Checkout. Notes: See paypal-nvp-express-checkout-how-to.md Author: G. D. LaBossiere, Xview Solutions Inc. Release: 1 Date: 2022-01-20 RCS: $Id$ License: GNU GPL v3 __comments__ #------------------------------------------------------------------------------ # bash environment #------------------------------------------------------------------------------ # BASH_VERSINFO[@] # FUNCNAME #------------------------------------------------------------------------------ # constants #------------------------------------------------------------------------------ PAYPAL_BRANDNAME="" PAYPAL_CANCELURL="" PAYPAL_CHECKOUT_URL="https://www.sandbox.paypal.com/checkoutnow" PAYPAL_CURRENCIES=('USD') PAYPAL_LOGOIMG="" PAYPAL_METHOD="SetExpressCheckout" PAYPAL_NVP_URL="https://api-3t.sandbox.paypal.com/nvp" PAYPAL_PWD="" PAYPAL_SIGNATURE="" PAYPAL_RETURNURL="" PAYPAL_USER="" #------------------------------------------------------------------------------ # error codes #------------------------------------------------------------------------------ ERROR_10="Requires bash 4.2+" ERROR_15="Missing required program(s)" ERROR_17="Required global(s) unset" #------------------------------------------------------------------------------ # variables #------------------------------------------------------------------------------ argList=() currencyCode="" errFuncName="" errorNumber="" invoiceId="" paymentAmount="" paypalReply="" showUsage="" #------------------------------------------------------------------------------ # functions #------------------------------------------------------------------------------ exit_handler() { errorNumber="$?" [[ $errorNumber -eq 0 ]] && return 0 local errtxt="ERROR_${errorNumber}" local errmsg="Error ${errorNumber}: No description available" [[ ${!errtxt} ]] && errmsg="Error ${errorNumber}: ${!errtxt}" [[ ${errFuncName} ]] && errmsg="${errFuncName}: ${errmsg}" errmsg="${0##*/}: ${errmsg}" printf '%s\n' "${errmsg}" return $errorNumber } #------------------------------------------------------------------------------ generate_reply() { [[ $showUsage ]] && return 0 errFuncName="$FUNCNAME" type -p curl &>/dev/null || exit 15 local args args="-d METHOD=${PAYPAL_METHOD} -d VERSION=100 -d CHANNELTYPE=Merchant" args="${args} -d SOLUTIONTYPE=Sole -d LANDINGPAGE=Billing -d NOSHIPPING=1" args="${args} -d PAYMENTREQUEST_0_PAYMENTACTION=Sale -d TOTALTYPE=Total" args="${args} -d USERSELECTEDFUNDINGSOURCE=CreditCard" args="${args} -d CANCELURL=${PAYPAL_CANCELURL}" args="${args} -d PWD=${PAYPAL_PWD}" args="${args} -d SIGNATURE=${PAYPAL_SIGNATURE}" args="${args} -d RETURNURL=${PAYPAL_RETURNURL}" args="${args} -d USER=${PAYPAL_USER}" args="${args} -d PAYMENTREQUEST_0_CURRENCYCODE=${currencyCode}" args="${args} -d PAYMENTREQUEST_0_AMT=${paymentAmount}" args="${args} -d PAYMENTREQUEST_0_ITEMAMT=${paymentAmount}" [[ $PAYPAL_BRANDNAME ]] && PAYPAL_BRANDNAME="${PAYPAL_BRANDNAME// /%20}" [[ $PAYPAL_BRANDNAME ]] && args="${args} -d BRANDNAME=${PAYPAL_BRANDNAME}" [[ $PAYPAL_LOGOIMG ]] && args="${args} -d LOGOIMG=${PAYPAL_LOGOIMG}" [[ $invoiceId ]] && args="${args} -d PAYMENTREQUEST_0_INVNUM=${invoiceId}" paypalReply=$(curl ${PAYPAL_NVP_URL} -s -k -m 10 ${args}) return 0 } #------------------------------------------------------------------------------ parse_command_line() { errFuncName="$FUNCNAME" local arg=0 args=("${argList[@]}") [[ ${#args[@]} -lt 6 ]] && showUsage="true" && return 0 while [[ $arg -lt ${#args[@]} ]]; do case "${args[$arg]}" in -a|--amount) ((++arg)) paymentAmount="${args[$arg]}" [[ $paymentAmount =~ ^[1-9]{1}[0-9]*(\.[0-9]{1,2})*$ ]] || \ paymentAmount="" ((++arg)) ;; -c|--currency) ((++arg)) currencyCode="${args[$arg]^^}" [[ ${PAYPAL_CURRENCIES[@]^^} =~ $currencyCode ]] || currencyCode="" [[ ${#currencyCode} -eq 3 ]] || currencyCode="" ((++arg)) ;; -i|--invoice) ((++arg)) invoiceId="${args[$arg]}" [[ $invoiceId =~ ^([0-9a-zA-Z]{0,256})$ ]] || invoiceId="" ((++arg)) ;; *) ((++arg)) ;; esac done [[ $currencyCode && $paymentAmount ]] || showUsage="true" return 0 } #------------------------------------------------------------------------------ print_reply() { [[ $showUsage ]] && return 0 errFuncName="$FUNCNAME" [[ $paypalReply ]] || exit 17 type -p cgi2shell &>/dev/null || exit 15 local i token # replace ampersands with newlines; read newline-delimited string into array readarray -t paypalReply <<< "${paypalReply//\&/$'\n'}" # convert the url-encoded array elements to name="value" shell format; save #+ the result as a string containing newlines paypalReply=$(cgi2shell "${paypalReply[@]}") # read the string contents back into an array readarray -t paypalReply <<< "${paypalReply}" # parse the array for the paypal token value for ((i=0;i<${#paypalReply[@]};i++)); do [[ ${paypalReply[$i]^^} =~ ^TOKEN= ]] && \ token="${paypalReply[$i]//\"/}" && token="${token#*\=}" && break 1 done # print each element of the array in name="value" shell format printf '%s\n' "${paypalReply[@]}" # compose and print the checkout url [[ $token ]] && printf '\n\t%s\n\n' \ "Express checkout url is: ${PAYPAL_CHECKOUT_URL}?token=${token}" return 0 } #------------------------------------------------------------------------------ show_usage() { [[ $showUsage ]] || return 0 errFuncName="$FUNCNAME" printf '%b' " ------------------------------------------------------------------------------- Usage: ${0##*/} ARGUMENTS Send a curl request for a PayPal express checkout session token in NVP format to ${PAYPAL_NVP_URL} Parse and print the \$QUERY_STRING reply to stdout in shell format. Print the PayPal express checkout url with token appended to stdout. Arguments: -a|--amount 0000|0000.00 Required. The payment amount must be an integer or decimal value. Maximum 2 significant digits. -c|--currency $(printf '%s ' "${PAYPAL_CURRENCIES[@]}") Required. The ISO currency code of the payment must be one of the values shown. -i|--invoice IDENTIFIER Optional. A unique invoice or order IDENTIFIER which must be 256 or fewer alphanumeric characters. Missing or invalid arguments cause this message to be displayed. ------------------------------------------------------------------------------- " return 0 } #------------------------------------------------------------------------------ # main #------------------------------------------------------------------------------ main() { trap exit_handler EXIT argList=("$@") [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -ge 2 ]] || \ [[ ${BASH_VERSINFO[0]} -gt 4 ]] || exit 10 parse_command_line generate_reply print_reply show_usage exit 0 } #------------------------------------------------------------------------------ # run program #------------------------------------------------------------------------------ main "$@"