2012-05-26 16:25:07 +00:00
< ? php
2013-02-20 17:14:46 +00:00
2014-09-20 19:42:58 +00:00
if ( ! defined ( 'ABSPATH' ) ) {
exit ; // Exit if accessed directly
}
2013-02-20 17:14:46 +00:00
2012-05-26 16:25:07 +00:00
/**
* PayPal Standard Payment Gateway
2012-08-10 13:09:02 +00:00
*
2012-05-26 16:25:07 +00:00
* Provides a PayPal Standard Payment Gateway .
*
* @ class WC_Paypal
2012-12-31 18:25:09 +00:00
* @ extends WC_Gateway_Paypal
2014-10-21 21:31:37 +00:00
* @ version 2.3 . 0
2012-08-15 18:15:06 +00:00
* @ package WooCommerce / Classes / Payment
* @ author WooThemes
2012-05-26 16:25:07 +00:00
*/
2012-12-31 18:25:09 +00:00
class WC_Gateway_Paypal extends WC_Payment_Gateway {
2012-11-27 16:22:47 +00:00
2012-09-12 12:36:34 +00:00
var $notify_url ;
2012-11-27 16:22:47 +00:00
2013-12-31 12:45:02 +00:00
/**
* Constructor for the gateway .
*/
2012-08-10 13:09:02 +00:00
public function __construct () {
2014-10-23 13:27:24 +00:00
$this -> id = 'paypal' ;
$this -> has_fields = false ;
$this -> order_button_text = __ ( 'Proceed to PayPal' , 'woocommerce' );
$this -> liveurl = 'https://www.paypal.com/cgi-bin/webscr' ;
$this -> testurl = 'https://www.sandbox.paypal.com/cgi-bin/webscr' ;
$this -> method_title = __ ( 'PayPal' , 'woocommerce' );
$this -> method_description = __ ( 'PayPal standard works by sending the user to PayPal to enter their payment information.' , 'woocommerce' );
$this -> notify_url = WC () -> api_request_url ( 'WC_Gateway_Paypal' );
$this -> supports = array (
2014-07-07 10:44:15 +00:00
'products' ,
'refunds'
);
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Load the settings.
2013-01-02 13:38:33 +00:00
$this -> init_form_fields ();
2012-05-26 16:25:07 +00:00
$this -> init_settings ();
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Define user set variables
2012-12-31 12:07:43 +00:00
$this -> title = $this -> get_option ( 'title' );
$this -> description = $this -> get_option ( 'description' );
$this -> email = $this -> get_option ( 'email' );
2013-03-11 10:36:51 +00:00
$this -> receiver_email = $this -> get_option ( 'receiver_email' , $this -> email );
2012-12-31 12:07:43 +00:00
$this -> testmode = $this -> get_option ( 'testmode' );
$this -> send_shipping = $this -> get_option ( 'send_shipping' );
$this -> address_override = $this -> get_option ( 'address_override' );
$this -> debug = $this -> get_option ( 'debug' );
$this -> page_style = $this -> get_option ( 'page_style' );
$this -> invoice_prefix = $this -> get_option ( 'invoice_prefix' , 'WC-' );
2013-07-23 09:18:58 +00:00
$this -> paymentaction = $this -> get_option ( 'paymentaction' , 'sale' );
2013-08-19 11:28:29 +00:00
$this -> identity_token = $this -> get_option ( 'identity_token' , '' );
2014-07-07 10:44:15 +00:00
$this -> api_username = $this -> get_option ( 'api_username' );
$this -> api_password = $this -> get_option ( 'api_password' );
$this -> api_signature = $this -> get_option ( 'api_signature' );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Logs
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-09-12 13:41:02 +00:00
$this -> log = new WC_Logger ();
2013-12-31 12:53:55 +00:00
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Actions
2012-12-15 11:53:32 +00:00
add_action ( 'valid-paypal-standard-ipn-request' , array ( $this , 'successful_request' ) );
2012-12-31 18:25:09 +00:00
add_action ( 'woocommerce_update_options_payment_gateways_' . $this -> id , array ( $this , 'process_admin_options' ) );
2013-08-19 11:28:29 +00:00
add_action ( 'woocommerce_thankyou_paypal' , array ( $this , 'pdt_return_handler' ) );
2012-11-27 16:22:47 +00:00
2012-09-12 12:36:34 +00:00
// Payment listener/API hook
2012-12-31 18:25:09 +00:00
add_action ( 'woocommerce_api_wc_gateway_paypal' , array ( $this , 'check_ipn_response' ) );
2012-08-10 13:09:02 +00:00
2013-12-31 12:53:55 +00:00
if ( ! $this -> is_valid_for_use () ) {
2014-09-29 10:08:19 +00:00
$this -> enabled = 'no' ;
2013-12-31 12:53:55 +00:00
}
2013-12-31 12:45:02 +00:00
}
2012-08-10 13:09:02 +00:00
2014-09-19 15:55:14 +00:00
/**
* get_icon function .
*
* @ return string
*/
public function get_icon () {
$link = null ;
switch ( WC () -> countries -> get_base_country () ) {
case 'US' :
case 'NZ' :
case 'CZ' :
case 'HU' :
case 'MY' :
$icon = 'https://www.paypalobjects.com/webstatic/mktg/logo/AM_mc_vs_dc_ae.jpg' ;
break ;
case 'TR' :
$icon = 'https://www.paypalobjects.com/webstatic/mktg/logo-center/logo_paypal_odeme_secenekleri.jpg' ;
break ;
case 'GB' :
$icon = 'https://www.paypalobjects.com/webstatic/mktg/Logo/AM_mc_vs_ms_ae_UK.png' ;
break ;
case 'MX' :
$icon = array (
'https://www.paypal.com/es_XC/Marketing/i/banner/paypal_visa_mastercard_amex.png' ,
'https://www.paypal.com/es_XC/Marketing/i/banner/paypal_debit_card_275x60.gif'
);
$link = 'https://www.paypal.com/mx/cgi-bin/webscr?cmd=xpt/Marketing/general/WIPaypal-outside' ;
break ;
case 'FR' :
$icon = 'https://www.paypalobjects.com/webstatic/mktg/logo-center/logo_paypal_moyens_paiement_fr.jpg' ;
break ;
case 'AU' :
$icon = 'https://www.paypalobjects.com/webstatic/en_AU/mktg/logo/Solutions-graphics-1-184x80.jpg' ;
break ;
case 'DK' :
$icon = 'https://www.paypalobjects.com/webstatic/mktg/logo-center/logo_PayPal_betalingsmuligheder_dk.jpg' ;
break ;
case 'RU' :
$icon = 'https://www.paypalobjects.com/webstatic/ru_RU/mktg/business/pages/logo-center/AM_mc_vs_dc_ae.jpg' ;
break ;
case 'NO' :
$icon = 'https://www.paypalobjects.com/webstatic/mktg/logo-center/banner_pl_just_pp_319x110.jpg' ;
break ;
case 'CA' :
$icon = 'https://www.paypalobjects.com/webstatic/en_CA/mktg/logo-image/AM_mc_vs_dc_ae.jpg' ;
break ;
case 'HK' :
$icon = 'https://www.paypalobjects.com/webstatic/en_HK/mktg/logo/AM_mc_vs_dc_ae.jpg' ;
break ;
case 'SG' :
$icon = 'https://www.paypalobjects.com/webstatic/en_SG/mktg/Logos/AM_mc_vs_dc_ae.jpg' ;
break ;
case 'TW' :
$icon = 'https://www.paypalobjects.com/webstatic/en_TW/mktg/logos/AM_mc_vs_dc_ae.jpg' ;
break ;
case 'TH' :
$icon = 'https://www.paypalobjects.com/webstatic/en_TH/mktg/Logos/AM_mc_vs_dc_ae.jpg' ;
break ;
default :
$icon = WC_HTTPS :: force_https_url ( WC () -> plugin_url () . '/includes/gateways/paypal/assets/images/paypal.png' );
$link = null ;
break ;
}
if ( is_null ( $link ) ) {
$link = 'https://www.paypal.com/' . strtolower ( WC () -> countries -> get_base_country () ) . '/webapps/mpp/paypal-popup' ;
}
if ( is_array ( $icon ) ) {
$icon_html = '' ;
foreach ( $icon as $i ) {
2014-10-21 21:31:37 +00:00
$icon_html .= '<img src="' . esc_attr ( $i ) . '" alt="' . __ ( 'PayPal Acceptance Mark' , 'woocommerce' ) . '" />' ;
2014-09-19 15:55:14 +00:00
}
} else {
2014-10-21 21:31:37 +00:00
$icon_html = '<img src="' . esc_attr ( apply_filters ( 'woocommerce_paypal_icon' , $icon ) ) . '" alt="' . __ ( 'PayPal Acceptance Mark' , 'woocommerce' ) . '" />' ;
2014-09-19 15:55:14 +00:00
}
if ( $link ) {
$what_is_paypal = sprintf ( '<a href="%1$s" class="about_paypal" onclick="javascript:window.open(\'%1$s\',\'WIPaypal\',\'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=1060, height=700\'); return false;" title="' . esc_attr__ ( 'What is PayPal?' , 'woocommerce' ) . '">' . esc_attr__ ( 'What is PayPal?' , 'woocommerce' ) . '</a>' , esc_url ( $link ) );
} else {
$what_is_paypal = '' ;
}
return apply_filters ( 'woocommerce_gateway_icon' , $icon_html . $what_is_paypal , $this -> id );
}
2013-12-31 12:45:02 +00:00
/**
* Check if this gateway is enabled and available in the user ' s country
*
* @ return bool
*/
function is_valid_for_use () {
2013-12-31 12:53:55 +00:00
if ( ! in_array ( get_woocommerce_currency (), apply_filters ( 'woocommerce_paypal_supported_currencies' , array ( 'AUD' , 'BRL' , 'CAD' , 'MXN' , 'NZD' , 'HKD' , 'SGD' , 'USD' , 'EUR' , 'JPY' , 'TRY' , 'NOK' , 'CZK' , 'DKK' , 'HUF' , 'ILS' , 'MYR' , 'PHP' , 'PLN' , 'SEK' , 'CHF' , 'TWD' , 'THB' , 'GBP' , 'RMB' , 'RUB' ) ) ) ) {
return false ;
}
2012-05-26 16:25:07 +00:00
2013-12-31 12:45:02 +00:00
return true ;
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
/**
2012-08-10 13:09:02 +00:00
* Admin Panel Options
2012-05-26 16:25:07 +00:00
* - Options for bits like 'title' and availability on a country - by - country basis
*
* @ since 1.0 . 0
*/
public function admin_options () {
2014-07-31 05:57:13 +00:00
if ( $this -> is_valid_for_use () ) {
parent :: admin_options ();
} else {
2012-12-31 12:07:43 +00:00
?>
2013-12-31 12:45:02 +00:00
< div class = " inline error " >< p >< strong >< ? php _e ( 'Gateway Disabled' , 'woocommerce' ); ?> </strong>: <?php _e( 'PayPal does not support your store currency.', 'woocommerce' ); ?></p></div>
2014-07-31 05:57:13 +00:00
< ? php
}
2012-12-27 10:44:58 +00:00
}
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
/**
* Initialise Gateway Settings Form Fields
*/
2014-07-07 10:44:15 +00:00
public function init_form_fields () {
2013-12-31 12:45:02 +00:00
$this -> form_fields = array (
2012-05-26 16:25:07 +00:00
'enabled' => array (
2013-08-19 11:28:29 +00:00
'title' => __ ( 'Enable/Disable' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Enable PayPal standard' , 'woocommerce' ),
'default' => 'yes'
),
2012-05-26 16:25:07 +00:00
'title' => array (
2013-08-19 11:28:29 +00:00
'title' => __ ( 'Title' , 'woocommerce' ),
'type' => 'text' ,
'description' => __ ( 'This controls the title which the user sees during checkout.' , 'woocommerce' ),
'default' => __ ( 'PayPal' , 'woocommerce' ),
'desc_tip' => true ,
),
2012-05-26 16:25:07 +00:00
'description' => array (
2013-08-19 11:28:29 +00:00
'title' => __ ( 'Description' , 'woocommerce' ),
2014-07-07 10:44:15 +00:00
'type' => 'text' ,
'desc_tip' => true ,
2013-08-19 11:28:29 +00:00
'description' => __ ( 'This controls the description which the user sees during checkout.' , 'woocommerce' ),
2014-09-19 15:55:14 +00:00
'default' => __ ( 'Pay via PayPal; you can pay with your credit card if you don\'t have a PayPal account.' , 'woocommerce' )
2013-08-19 11:28:29 +00:00
),
2012-05-26 16:25:07 +00:00
'email' => array (
2013-08-19 11:28:29 +00:00
'title' => __ ( 'PayPal Email' , 'woocommerce' ),
'type' => 'email' ,
'description' => __ ( 'Please enter your PayPal email address; this is needed in order to take payment.' , 'woocommerce' ),
'default' => '' ,
'desc_tip' => true ,
'placeholder' => 'you@youremail.com'
),
2014-07-07 10:44:15 +00:00
'testmode' => array (
'title' => __ ( 'PayPal sandbox' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Enable PayPal sandbox' , 'woocommerce' ),
'default' => 'no' ,
'description' => sprintf ( __ ( 'PayPal sandbox can be used to test payments. Sign up for a developer account <a href="%s">here</a>.' , 'woocommerce' ), 'https://developer.paypal.com/' ),
),
'debug' => array (
'title' => __ ( 'Debug Log' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Enable logging' , 'woocommerce' ),
'default' => 'no' ,
'description' => sprintf ( __ ( 'Log PayPal events, such as IPN requests, inside <code>%s</code>' , 'woocommerce' ), wc_get_log_file_path ( 'paypal' ) )
),
'shipping' => array (
'title' => __ ( 'Shipping options' , 'woocommerce' ),
'type' => 'title' ,
'description' => '' ,
),
'send_shipping' => array (
'title' => __ ( 'Shipping details' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Send shipping details to PayPal instead of billing.' , 'woocommerce' ),
'description' => __ ( 'PayPal allows us to send 1 address. If you are using PayPal for shipping labels you may prefer to send the shipping address rather than billing.' , 'woocommerce' ),
'default' => 'no'
),
'address_override' => array (
'title' => __ ( 'Address override' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Enable "address_override" to prevent address information from being changed.' , 'woocommerce' ),
'description' => __ ( 'PayPal verifies addresses therefore this setting can cause errors (we recommend keeping it disabled).' , 'woocommerce' ),
'default' => 'no'
),
'advanced' => array (
'title' => __ ( 'Advanced options' , 'woocommerce' ),
'type' => 'title' ,
'description' => '' ,
),
2013-03-11 10:36:51 +00:00
'receiver_email' => array (
2013-08-19 11:28:29 +00:00
'title' => __ ( 'Receiver Email' , 'woocommerce' ),
'type' => 'email' ,
2014-07-07 10:44:15 +00:00
'description' => __ ( 'If your main PayPal email differs from the PayPal email entered above, input your main receiver email for your PayPal account here. This is used to validate IPN requests.' , 'woocommerce' ),
2013-08-19 11:28:29 +00:00
'default' => '' ,
'desc_tip' => true ,
'placeholder' => 'you@youremail.com'
),
2012-08-10 13:09:02 +00:00
'invoice_prefix' => array (
2013-08-19 11:28:29 +00:00
'title' => __ ( 'Invoice Prefix' , 'woocommerce' ),
'type' => 'text' ,
'description' => __ ( 'Please enter a prefix for your invoice numbers. If you use your PayPal account for multiple stores ensure this prefix is unique as PayPal will not allow orders with the same invoice number.' , 'woocommerce' ),
'default' => 'WC-' ,
'desc_tip' => true ,
),
2013-07-23 09:18:58 +00:00
'paymentaction' => array (
2013-08-19 11:28:29 +00:00
'title' => __ ( 'Payment Action' , 'woocommerce' ),
'type' => 'select' ,
'description' => __ ( 'Choose whether you wish to capture funds immediately or authorize payment only.' , 'woocommerce' ),
'default' => 'sale' ,
'desc_tip' => true ,
'options' => array (
'sale' => __ ( 'Capture' , 'woocommerce' ),
'authorization' => __ ( 'Authorize' , 'woocommerce' )
)
),
2012-07-27 12:59:51 +00:00
'page_style' => array (
2013-08-19 11:28:29 +00:00
'title' => __ ( 'Page Style' , 'woocommerce' ),
'type' => 'text' ,
'description' => __ ( 'Optionally enter the name of the page style you wish to use. These are defined within your PayPal account.' , 'woocommerce' ),
'default' => '' ,
'desc_tip' => true ,
'placeholder' => __ ( 'Optional' , 'woocommerce' )
),
2014-07-07 10:44:15 +00:00
'identity_token' => array (
'title' => __ ( 'PayPal Identity Token' , 'woocommerce' ),
'type' => 'text' ,
'description' => __ ( 'Optionally enable "Payment Data Transfer" (Profile > Website Payment Preferences) and then copy your identity token here. This will allow payments to be verified without the need for PayPal IPN.' , 'woocommerce' ),
'default' => '' ,
'desc_tip' => true ,
'placeholder' => __ ( 'Optional' , 'woocommerce' )
),
'api_details' => array (
2014-09-02 21:44:17 +00:00
'title' => __ ( 'API Credentials' , 'woocommerce' ),
2013-08-19 11:28:29 +00:00
'type' => 'title' ,
2014-09-02 21:44:17 +00:00
'description' => sprintf ( __ ( 'Enter your PayPal API credentials to process refunds via PayPal. Learn how to access your PayPal API Credentials %shere%s.' , 'woocommerce' ), '<a href="https://developer.paypal.com/webapps/developer/docs/classic/api/apiCredentials/#creating-classic-api-credentials">' , '</a>' ),
2013-08-19 11:28:29 +00:00
),
2014-07-07 10:44:15 +00:00
'api_username' => array (
'title' => __ ( 'API Username' , 'woocommerce' ),
'type' => 'text' ,
'description' => __ ( 'Get your API credentials from PayPal.' , 'woocommerce' ),
'default' => '' ,
'desc_tip' => true ,
'placeholder' => __ ( 'Optional' , 'woocommerce' )
2013-08-19 11:28:29 +00:00
),
2014-07-07 10:44:15 +00:00
'api_password' => array (
'title' => __ ( 'API Password' , 'woocommerce' ),
'type' => 'text' ,
'description' => __ ( 'Get your API credentials from PayPal.' , 'woocommerce' ),
'default' => '' ,
'desc_tip' => true ,
'placeholder' => __ ( 'Optional' , 'woocommerce' )
2013-08-19 11:28:29 +00:00
),
2014-07-07 10:44:15 +00:00
'api_signature' => array (
'title' => __ ( 'API Signature' , 'woocommerce' ),
'type' => 'text' ,
'description' => __ ( 'Get your API credentials from PayPal.' , 'woocommerce' ),
'default' => '' ,
'desc_tip' => true ,
'placeholder' => __ ( 'Optional' , 'woocommerce' )
2013-08-19 11:28:29 +00:00
),
);
2013-12-31 12:45:02 +00:00
}
2012-08-10 13:09:02 +00:00
2014-02-24 14:49:01 +00:00
/**
* Limit the length of item names
* @ param string $item_name
* @ return string
*/
public function paypal_item_name ( $item_name ) {
if ( strlen ( $item_name ) > 127 ) {
$item_name = substr ( $item_name , 0 , 124 ) . '...' ;
}
return html_entity_decode ( $item_name , ENT_NOQUOTES , 'UTF-8' );
}
2012-08-15 18:15:06 +00:00
/**
2012-05-26 16:25:07 +00:00
* Get PayPal Args for passing to PP
2012-08-15 18:15:06 +00:00
*
2014-10-23 13:27:24 +00:00
* @ param WC_Order $order
2012-08-15 18:15:06 +00:00
* @ return array
*/
2012-05-26 16:25:07 +00:00
function get_paypal_args ( $order ) {
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
$order_id = $order -> id ;
2012-08-10 13:09:02 +00:00
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2014-10-24 13:53:40 +00:00
$this -> log -> add ( 'paypal' , 'Generating payment form for order #' . $order -> get_order_number () . '. Notify URL: ' . $this -> notify_url );
2013-12-31 12:53:55 +00:00
}
2012-08-10 13:09:02 +00:00
2012-10-20 14:40:27 +00:00
if ( in_array ( $order -> billing_country , array ( 'US' , 'CA' ) ) ) {
2013-07-19 06:00:38 +00:00
$order -> billing_phone = str_replace ( array ( '(' , '-' , ' ' , ')' , '.' ), '' , $order -> billing_phone );
2012-05-26 16:25:07 +00:00
$phone_args = array (
2012-10-20 14:40:27 +00:00
'night_phone_a' => substr ( $order -> billing_phone , 0 , 3 ),
'night_phone_b' => substr ( $order -> billing_phone , 3 , 3 ),
'night_phone_c' => substr ( $order -> billing_phone , 6 , 4 ),
'day_phone_a' => substr ( $order -> billing_phone , 0 , 3 ),
'day_phone_b' => substr ( $order -> billing_phone , 3 , 3 ),
'day_phone_c' => substr ( $order -> billing_phone , 6 , 4 )
2012-05-26 16:25:07 +00:00
);
2012-10-20 14:40:27 +00:00
} else {
2012-05-26 16:25:07 +00:00
$phone_args = array (
'night_phone_b' => $order -> billing_phone ,
'day_phone_b' => $order -> billing_phone
);
2012-10-20 14:40:27 +00:00
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// PayPal Args
$paypal_args = array_merge (
array (
2014-02-13 12:31:32 +00:00
'cmd' => '_cart' ,
'business' => $this -> email ,
'no_note' => 1 ,
'currency_code' => get_woocommerce_currency (),
2014-10-23 13:27:24 +00:00
'charset' => 'utf-8' ,
2014-02-13 12:31:32 +00:00
'rm' => is_ssl () ? 2 : 1 ,
'upload' => 1 ,
2014-10-23 14:47:21 +00:00
'return' => esc_url ( add_query_arg ( 'utm_nooverride' , '1' , $this -> get_return_url ( $order ) ) ),
'cancel_return' => esc_url ( $order -> get_cancel_order_url () ),
2014-02-13 12:31:32 +00:00
'page_style' => $this -> page_style ,
'paymentaction' => $this -> paymentaction ,
'bn' => 'WooThemes_Cart' ,
2014-05-28 14:08:33 +00:00
2012-08-10 13:09:02 +00:00
// Order key + ID
2014-10-24 13:53:40 +00:00
'invoice' => $this -> invoice_prefix . $order -> get_order_number (),
2014-02-13 12:31:32 +00:00
'custom' => serialize ( array ( $order_id , $order -> order_key ) ),
2014-05-28 14:08:33 +00:00
2012-05-26 16:25:07 +00:00
// IPN
2014-02-13 12:31:32 +00:00
'notify_url' => $this -> notify_url ,
2014-05-28 14:08:33 +00:00
2012-05-26 16:25:07 +00:00
// Billing Address info
2014-02-13 12:31:32 +00:00
'first_name' => $order -> billing_first_name ,
'last_name' => $order -> billing_last_name ,
'company' => $order -> billing_company ,
'address1' => $order -> billing_address_1 ,
'address2' => $order -> billing_address_2 ,
'city' => $order -> billing_city ,
2014-03-17 15:23:11 +00:00
'state' => $this -> get_paypal_state ( $order -> billing_country , $order -> billing_state ),
2014-02-13 12:31:32 +00:00
'zip' => $order -> billing_postcode ,
'country' => $order -> billing_country ,
'email' => $order -> billing_email
2012-08-10 13:09:02 +00:00
),
2012-05-26 16:25:07 +00:00
$phone_args
);
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Shipping
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> send_shipping ) {
2012-05-26 16:25:07 +00:00
$paypal_args [ 'address_override' ] = ( $this -> address_override == 'yes' ) ? 1 : 0 ;
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
$paypal_args [ 'no_shipping' ] = 0 ;
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// If we are sending shipping, send shipping address instead of billing
$paypal_args [ 'first_name' ] = $order -> shipping_first_name ;
$paypal_args [ 'last_name' ] = $order -> shipping_last_name ;
$paypal_args [ 'company' ] = $order -> shipping_company ;
$paypal_args [ 'address1' ] = $order -> shipping_address_1 ;
$paypal_args [ 'address2' ] = $order -> shipping_address_2 ;
$paypal_args [ 'city' ] = $order -> shipping_city ;
2014-03-17 15:23:11 +00:00
$paypal_args [ 'state' ] = $this -> get_paypal_state ( $order -> shipping_country , $order -> shipping_state );
2012-05-26 16:25:07 +00:00
$paypal_args [ 'country' ] = $order -> shipping_country ;
$paypal_args [ 'zip' ] = $order -> shipping_postcode ;
} else {
$paypal_args [ 'no_shipping' ] = 1 ;
}
2012-08-10 13:09:02 +00:00
2014-07-31 05:57:13 +00:00
// Try to send line items, or default to sending the order as a whole
if ( $line_items = $this -> get_line_items ( $order ) ) {
$paypal_args = array_merge ( $paypal_args , $line_items );
} else {
2012-05-26 16:25:07 +00:00
// Don't pass items - paypal borks tax due to prices including tax. PayPal has no option for tax inclusive pricing sadly. Pass 1 item for the order items overall
$item_names = array ();
2012-08-10 13:09:02 +00:00
2013-12-31 12:53:55 +00:00
if ( sizeof ( $order -> get_items () ) > 0 ) {
foreach ( $order -> get_items () as $item ) {
if ( $item [ 'qty' ] ) {
2012-10-20 14:40:27 +00:00
$item_names [] = $item [ 'name' ] . ' x ' . $item [ 'qty' ];
2013-12-31 12:53:55 +00:00
}
}
}
2012-08-10 13:09:02 +00:00
2014-10-24 13:53:40 +00:00
$paypal_args [ 'item_name_1' ] = $this -> paypal_item_name ( sprintf ( __ ( 'Order #%s' , 'woocommerce' ), $order -> get_order_number () ) . " - " . implode ( ', ' , $item_names ) );
2014-09-15 15:38:07 +00:00
$paypal_args [ 'quantity_1' ] = '1' ;
2014-07-31 05:57:13 +00:00
$paypal_args [ 'amount_1' ] = number_format ( $order -> get_total () - round ( $order -> get_total_shipping () + $order -> get_shipping_tax (), 2 ) + $order -> get_order_discount (), 2 , '.' , '' );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Shipping Cost
2012-08-10 13:09:02 +00:00
// No longer using shipping_1 because
2012-07-27 12:59:51 +00:00
// a) paypal ignore it if *any* shipping rules are within paypal
2013-03-03 17:07:31 +00:00
// b) paypal ignore anything over 5 digits, so 999.99 is the max
2013-10-17 11:43:44 +00:00
if ( ( $order -> get_total_shipping () + $order -> get_shipping_tax () ) > 0 ) {
2014-02-24 14:49:01 +00:00
$paypal_args [ 'item_name_2' ] = $this -> paypal_item_name ( __ ( 'Shipping via' , 'woocommerce' ) . ' ' . ucwords ( $order -> get_shipping_method () ) );
2012-05-26 16:25:07 +00:00
$paypal_args [ 'quantity_2' ] = '1' ;
2014-02-20 15:41:08 +00:00
$paypal_args [ 'amount_2' ] = number_format ( $order -> get_total_shipping () + $order -> get_shipping_tax (), 2 , '.' , '' );
2012-10-20 14:40:27 +00:00
}
2014-09-15 15:38:07 +00:00
// Discount
if ( $order -> get_order_discount () ) {
$paypal_args [ 'discount_amount_cart' ] = $order -> get_order_discount ();
}
2014-07-31 05:57:13 +00:00
}
2012-08-10 13:09:02 +00:00
2014-07-31 05:57:13 +00:00
$paypal_args = apply_filters ( 'woocommerce_paypal_args' , $paypal_args );
2012-05-26 16:25:07 +00:00
2014-07-31 05:57:13 +00:00
return $paypal_args ;
}
2012-11-27 16:22:47 +00:00
2014-07-31 05:57:13 +00:00
/**
* Get line items to send to paypal
*
* @ param WC_Order $order
* @ return array on success , or false when it is not possible to send line items
*/
private function get_line_items ( $order ) {
// Do not send lines for tax inclusive prices
if ( 'yes' === get_option ( 'woocommerce_calc_taxes' ) && 'yes' === get_option ( 'woocommerce_prices_include_tax' ) ) {
return false ;
}
2012-11-27 16:22:47 +00:00
2014-07-31 05:57:13 +00:00
// Do not send lines when order discount is present, or too many line items in the order.
if ( $order -> get_order_discount () > 0 || ( sizeof ( $order -> get_items () ) + sizeof ( $order -> get_fees () ) ) >= 9 ) {
return false ;
}
2012-11-27 16:22:47 +00:00
2014-07-31 05:57:13 +00:00
$item_loop = 0 ;
$args = array ();
$args [ 'tax_cart' ] = $order -> get_total_tax ();
2014-11-13 13:41:47 +00:00
$calculated_total = $order -> get_total_tax ();
2014-08-07 18:57:29 +00:00
2014-07-31 05:57:13 +00:00
// Products
if ( sizeof ( $order -> get_items () ) > 0 ) {
foreach ( $order -> get_items () as $item ) {
if ( ! $item [ 'qty' ] ) {
continue ;
}
$item_loop ++ ;
$product = $order -> get_product_from_item ( $item );
$item_name = $item [ 'name' ];
$item_meta = new WC_Order_Item_Meta ( $item [ 'item_meta' ] );
2014-08-07 18:57:29 +00:00
2014-07-31 05:57:13 +00:00
if ( $meta = $item_meta -> display ( true , true ) ) {
$item_name .= ' ( ' . $meta . ' )' ;
}
2012-11-27 16:22:47 +00:00
2014-07-31 05:57:13 +00:00
$args [ 'item_name_' . $item_loop ] = $this -> paypal_item_name ( $item_name );
$args [ 'quantity_' . $item_loop ] = $item [ 'qty' ];
$args [ 'amount_' . $item_loop ] = $order -> get_item_subtotal ( $item , false );
2012-11-27 16:22:47 +00:00
2014-07-31 05:57:13 +00:00
if ( $args [ 'amount_' . $item_loop ] < 0 ) {
return false ; // Abort - negative line
}
2012-11-27 16:22:47 +00:00
2014-07-31 05:57:13 +00:00
if ( $product -> get_sku () ) {
$args [ 'item_number_' . $item_loop ] = $product -> get_sku ();
2012-10-20 14:40:27 +00:00
}
2014-11-13 13:41:47 +00:00
$calculated_total += $order -> get_item_subtotal ( $item , false ) * $item [ 'qty' ];
2012-10-20 14:40:27 +00:00
}
2014-07-31 05:57:13 +00:00
}
2012-11-27 16:22:47 +00:00
2014-07-31 05:57:13 +00:00
// Discount
if ( $order -> get_cart_discount () > 0 ) {
$args [ 'discount_amount_cart' ] = round ( $order -> get_cart_discount (), 2 );
2014-11-13 13:41:47 +00:00
$calculated_total = $calculated_total - round ( $order -> get_cart_discount (), 2 );
2014-07-31 05:57:13 +00:00
}
2013-03-25 14:46:08 +00:00
2014-07-31 05:57:13 +00:00
// Fees
if ( sizeof ( $order -> get_fees () ) > 0 ) {
foreach ( $order -> get_fees () as $item ) {
$item_loop ++ ;
$args [ 'item_name_' . $item_loop ] = $this -> paypal_item_name ( $item [ 'name' ] );
$args [ 'quantity_' . $item_loop ] = 1 ;
$args [ 'amount_' . $item_loop ] = $item [ 'line_total' ];
2012-11-27 16:22:47 +00:00
2014-07-31 05:57:13 +00:00
if ( $args [ 'amount_' . $item_loop ] < 0 ) {
return false ; // Abort - negative line
2012-11-12 17:15:54 +00:00
}
2014-11-13 13:41:47 +00:00
$calculated_total += $item [ 'line_total' ];
2012-11-12 17:15:54 +00:00
}
2012-10-20 14:40:27 +00:00
}
2012-08-10 13:09:02 +00:00
2014-07-31 05:57:13 +00:00
// Shipping Cost item - paypal only allows shipping per item, we want to send shipping for the order
if ( $order -> get_total_shipping () > 0 ) {
$item_loop ++ ;
$args [ 'item_name_' . $item_loop ] = $this -> paypal_item_name ( sprintf ( __ ( 'Shipping via %s' , 'woocommerce' ), $order -> get_shipping_method () ) );
$args [ 'quantity_' . $item_loop ] = '1' ;
$args [ 'amount_' . $item_loop ] = number_format ( $order -> get_total_shipping (), 2 , '.' , '' );
2014-11-13 13:41:47 +00:00
$calculated_total += number_format ( $order -> get_total_shipping (), 2 , '.' , '' );
}
// Check for mismatch
if ( $calculated_total != $order -> get_total () ) {
return false ;
2014-07-31 05:57:13 +00:00
}
2012-08-10 13:09:02 +00:00
2014-07-31 05:57:13 +00:00
return $args ;
2012-05-26 16:25:07 +00:00
}
2013-12-31 12:45:02 +00:00
/**
* Process the payment and return the result
*
* @ param int $order_id
* @ return array
*/
2014-07-07 10:44:15 +00:00
public function process_payment ( $order_id ) {
2014-08-15 12:29:21 +00:00
$order = wc_get_order ( $order_id );
2014-07-07 10:44:15 +00:00
$paypal_args = $this -> get_paypal_args ( $order );
$paypal_args = http_build_query ( $paypal_args , '' , '&' );
if ( 'yes' == $this -> testmode ) {
$paypal_adr = $this -> testurl . '?test_ipn=1&' ;
} else {
$paypal_adr = $this -> liveurl . '?' ;
}
return array (
'result' => 'success' ,
'redirect' => $paypal_adr . $paypal_args
);
}
2012-08-10 13:09:02 +00:00
2014-07-07 10:44:15 +00:00
/**
* Process a refund if supported
* @ param int $order_id
* @ param float $amount
2014-08-07 18:57:29 +00:00
* @ param string $reason
2014-07-07 10:44:15 +00:00
* @ return bool | wp_error True or false based on success , or a WP_Error object
*/
2014-08-11 13:07:09 +00:00
public function process_refund ( $order_id , $amount = null , $reason = '' ) {
2014-08-15 12:29:21 +00:00
$order = wc_get_order ( $order_id );
2012-08-10 13:09:02 +00:00
2014-08-21 19:17:12 +00:00
if ( ! $order || ! $order -> get_transaction_id () || ! $this -> api_username || ! $this -> api_password || ! $this -> api_signature ) {
2014-07-07 10:44:15 +00:00
return false ;
}
2012-08-10 13:09:02 +00:00
2014-07-07 10:44:15 +00:00
$post_data = array (
'VERSION' => '84.0' ,
'SIGNATURE' => $this -> api_signature ,
'USER' => $this -> api_username ,
'PWD' => $this -> api_password ,
'METHOD' => 'RefundTransaction' ,
'TRANSACTIONID' => $order -> get_transaction_id (),
'REFUNDTYPE' => is_null ( $amount ) ? 'Full' : 'Partial'
);
2012-08-10 13:09:02 +00:00
2014-07-07 10:44:15 +00:00
if ( ! is_null ( $amount ) ) {
$post_data [ 'AMT' ] = number_format ( $amount , 2 , '.' , '' );
$post_data [ 'CURRENCYCODE' ] = $order -> get_order_currency ();
}
2012-08-10 13:09:02 +00:00
2014-08-21 23:22:28 +00:00
if ( $reason ) {
if ( 255 < strlen ( $reason ) ) {
$reason = substr ( $reason , 0 , 252 ) . '...' ;
}
$post_data [ 'NOTE' ] = html_entity_decode ( $reason , ENT_NOQUOTES , 'UTF-8' );
}
2014-07-07 10:44:15 +00:00
$response = wp_remote_post ( 'yes' === $this -> testmode ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp' , array (
'method' => 'POST' ,
'body' => $post_data ,
'timeout' => 70 ,
'sslverify' => false ,
'user-agent' => 'WooCommerce' ,
'httpversion' => '1.1'
2014-08-07 18:57:29 +00:00
)
2014-07-07 10:44:15 +00:00
);
2012-08-10 13:09:02 +00:00
2014-07-07 10:44:15 +00:00
if ( is_wp_error ( $response ) ) {
return $response ;
}
2012-08-10 13:09:02 +00:00
2014-07-07 10:44:15 +00:00
if ( empty ( $response [ 'body' ] ) ) {
return new WP_Error ( 'paypal-error' , __ ( 'Empty Paypal response.' , 'woocommerce' ) );
}
2012-08-10 13:09:02 +00:00
2014-07-07 10:44:15 +00:00
parse_str ( $response [ 'body' ], $parsed_response );
2012-08-10 13:09:02 +00:00
2014-07-07 10:44:15 +00:00
switch ( strtolower ( $parsed_response [ 'ACK' ] ) ) {
case 'success' :
case 'successwithwarning' :
$order -> add_order_note ( sprintf ( __ ( 'Refunded %s - Refund ID: %s' , 'woocommerce' ), $parsed_response [ 'GROSSREFUNDAMT' ], $parsed_response [ 'REFUNDTRANSACTIONID' ] ) );
return true ;
break ;
2012-05-26 16:25:07 +00:00
}
2012-08-10 13:09:02 +00:00
2014-07-07 10:44:15 +00:00
return false ;
2012-05-26 16:25:07 +00:00
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
/**
* Check PayPal IPN validity
**/
2014-07-31 05:57:13 +00:00
public function check_ipn_request_is_valid ( $ipn_response ) {
2013-06-03 15:07:18 +00:00
// Get url
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> testmode ) {
2013-06-03 15:07:18 +00:00
$paypal_adr = $this -> testurl ;
2013-12-31 12:53:55 +00:00
} else {
2013-06-03 15:07:18 +00:00
$paypal_adr = $this -> liveurl ;
2013-12-31 12:53:55 +00:00
}
2013-06-03 15:07:18 +00:00
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-06-03 15:07:18 +00:00
$this -> log -> add ( 'paypal' , 'Checking IPN response is valid via ' . $paypal_adr . '...' );
2013-12-31 12:53:55 +00:00
}
2012-08-10 13:09:02 +00:00
2014-04-15 15:56:35 +00:00
// Get received values from post data
2014-01-30 14:46:23 +00:00
$validate_ipn = array ( 'cmd' => '_notify-validate' );
$validate_ipn += stripslashes_deep ( $ipn_response );
2012-05-26 16:25:07 +00:00
2013-12-31 12:45:02 +00:00
// Send back post vars to paypal
$params = array (
2014-01-30 14:46:23 +00:00
'body' => $validate_ipn ,
2013-12-31 12:45:02 +00:00
'sslverify' => false ,
'timeout' => 60 ,
'httpversion' => '1.1' ,
2014-01-13 12:22:52 +00:00
'compress' => false ,
'decompress' => false ,
2013-12-31 12:45:02 +00:00
'user-agent' => 'WooCommerce/' . WC () -> version
);
2012-05-26 16:25:07 +00:00
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-03-13 11:58:47 +00:00
$this -> log -> add ( 'paypal' , 'IPN Request: ' . print_r ( $params , true ) );
2013-12-31 12:53:55 +00:00
}
2013-03-13 11:58:47 +00:00
2012-05-26 16:25:07 +00:00
// Post back to get a response
2013-12-31 12:45:02 +00:00
$response = wp_remote_post ( $paypal_adr , $params );
2012-08-10 13:09:02 +00:00
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-12-31 12:45:02 +00:00
$this -> log -> add ( 'paypal' , 'IPN Response: ' . print_r ( $response , true ) );
2013-12-31 12:53:55 +00:00
}
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
// check to see if the request was valid
2014-08-05 20:12:52 +00:00
if ( ! is_wp_error ( $response ) && $response [ 'response' ][ 'code' ] >= 200 && $response [ 'response' ][ 'code' ] < 300 && strstr ( $response [ 'body' ], 'VERIFIED' ) ) {
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-12-31 12:45:02 +00:00
$this -> log -> add ( 'paypal' , 'Received valid response from PayPal' );
2013-12-31 12:53:55 +00:00
}
2012-11-27 16:22:47 +00:00
2013-12-31 12:45:02 +00:00
return true ;
}
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
if ( 'yes' == $this -> debug ) {
$this -> log -> add ( 'paypal' , 'Received invalid response from PayPal' );
2013-12-31 12:53:55 +00:00
if ( is_wp_error ( $response ) ) {
2013-12-31 12:45:02 +00:00
$this -> log -> add ( 'paypal' , 'Error response: ' . $response -> get_error_message () );
2013-12-31 12:53:55 +00:00
}
2013-12-31 12:45:02 +00:00
}
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
return false ;
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
/**
* Check for PayPal IPN Response
2012-08-15 18:15:06 +00:00
*/
2014-07-31 05:57:13 +00:00
public function check_ipn_response () {
2012-08-10 13:09:02 +00:00
2012-09-12 12:36:34 +00:00
@ ob_clean ();
2012-08-10 13:09:02 +00:00
2014-01-30 14:46:23 +00:00
$ipn_response = ! empty ( $_POST ) ? $_POST : false ;
if ( $ipn_response && $this -> check_ipn_request_is_valid ( $ipn_response ) ) {
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
header ( 'HTTP/1.1 200 OK' );
2012-08-10 13:09:02 +00:00
2014-01-30 14:46:23 +00:00
do_action ( " valid-paypal-standard-ipn-request " , $ipn_response );
2012-08-10 13:09:02 +00:00
2012-09-12 12:36:34 +00:00
} else {
2012-08-10 13:09:02 +00:00
2013-06-03 15:07:18 +00:00
wp_die ( " PayPal IPN Request Failure " , " PayPal IPN " , array ( 'response' => 200 ) );
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
/**
* Successful Payment !
2012-08-15 18:15:06 +00:00
*
* @ param array $posted
*/
2014-07-31 05:57:13 +00:00
public function successful_request ( $posted ) {
2012-08-10 13:09:02 +00:00
2013-03-13 11:58:47 +00:00
$posted = stripslashes_deep ( $posted );
2012-05-26 16:25:07 +00:00
// Custom holds post ID
2013-12-31 12:45:02 +00:00
if ( ! empty ( $posted [ 'invoice' ] ) && ! empty ( $posted [ 'custom' ] ) ) {
2012-11-27 16:22:47 +00:00
2013-12-31 12:45:02 +00:00
$order = $this -> get_paypal_order ( $posted [ 'custom' ], $posted [ 'invoice' ] );
2012-11-27 16:22:47 +00:00
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-12-31 12:45:02 +00:00
$this -> log -> add ( 'paypal' , 'Found order #' . $order -> id );
2013-12-31 12:53:55 +00:00
}
2013-03-13 11:58:47 +00:00
2013-12-31 12:45:02 +00:00
// Lowercase returned variables
$posted [ 'payment_status' ] = strtolower ( $posted [ 'payment_status' ] );
$posted [ 'txn_type' ] = strtolower ( $posted [ 'txn_type' ] );
2012-11-27 16:22:47 +00:00
2013-12-31 12:45:02 +00:00
// Sandbox fix
2013-12-31 12:53:55 +00:00
if ( 1 == $posted [ 'test_ipn' ] && 'pending' == $posted [ 'payment_status' ] ) {
2013-12-31 12:45:02 +00:00
$posted [ 'payment_status' ] = 'completed' ;
2013-12-31 12:53:55 +00:00
}
2013-03-27 22:39:55 +00:00
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-12-31 12:45:02 +00:00
$this -> log -> add ( 'paypal' , 'Payment status: ' . $posted [ 'payment_status' ] );
2013-12-31 12:53:55 +00:00
}
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
// We are here so lets check status and do actions
switch ( $posted [ 'payment_status' ] ) {
case 'completed' :
case 'pending' :
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
// Check order not already completed
2014-06-03 09:45:33 +00:00
if ( $order -> has_status ( 'completed' ) ) {
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-12-31 12:45:02 +00:00
$this -> log -> add ( 'paypal' , 'Aborting, Order #' . $order -> id . ' is already complete.' );
2013-12-31 12:53:55 +00:00
}
exit ;
2013-12-31 12:45:02 +00:00
}
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
// Check valid txn_type
$accepted_types = array ( 'cart' , 'instant' , 'express_checkout' , 'web_accept' , 'masspay' , 'send_money' );
2014-01-30 14:38:13 +00:00
2012-09-12 11:08:35 +00:00
if ( ! in_array ( $posted [ 'txn_type' ], $accepted_types ) ) {
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2012-09-12 11:08:35 +00:00
$this -> log -> add ( 'paypal' , 'Aborting, Invalid type:' . $posted [ 'txn_type' ] );
2013-12-31 12:53:55 +00:00
}
2012-05-26 16:25:07 +00:00
exit ;
2012-09-12 11:08:35 +00:00
}
2012-11-27 16:22:47 +00:00
2014-01-30 14:38:13 +00:00
// Validate currency
if ( $order -> get_order_currency () != $posted [ 'mc_currency' ] ) {
if ( 'yes' == $this -> debug ) {
2014-03-10 23:23:30 +00:00
$this -> log -> add ( 'paypal' , 'Payment error: Currencies do not match (sent "' . $order -> get_order_currency () . '" | returned "' . $posted [ 'mc_currency' ] . '")' );
2014-01-30 14:38:13 +00:00
}
// Put this order on-hold for manual checking
$order -> update_status ( 'on-hold' , sprintf ( __ ( 'Validation error: PayPal currencies do not match (code %s).' , 'woocommerce' ), $posted [ 'mc_currency' ] ) );
exit ;
}
2012-11-27 16:22:47 +00:00
2014-01-30 14:38:13 +00:00
// Validate amount
if ( $order -> get_total () != $posted [ 'mc_gross' ] ) {
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-12-31 12:45:02 +00:00
$this -> log -> add ( 'paypal' , 'Payment error: Amounts do not match (gross ' . $posted [ 'mc_gross' ] . ')' );
2013-12-31 12:53:55 +00:00
}
2012-11-27 16:22:47 +00:00
2013-12-31 12:45:02 +00:00
// Put this order on-hold for manual checking
$order -> update_status ( 'on-hold' , sprintf ( __ ( 'Validation error: PayPal amounts do not match (gross %s).' , 'woocommerce' ), $posted [ 'mc_gross' ] ) );
exit ;
}
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
// Validate Email Address
2013-03-11 10:36:51 +00:00
if ( strcasecmp ( trim ( $posted [ 'receiver_email' ] ), trim ( $this -> receiver_email ) ) != 0 ) {
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-03-11 10:36:51 +00:00
$this -> log -> add ( 'paypal' , " IPN Response is for another one: { $posted [ 'receiver_email' ] } our email is { $this -> receiver_email } " );
2013-12-31 12:53:55 +00:00
}
2013-03-10 13:51:59 +00:00
// Put this order on-hold for manual checking
2013-12-31 12:45:02 +00:00
$order -> update_status ( 'on-hold' , sprintf ( __ ( 'Validation error: PayPal IPN response from a different email address (%s).' , 'woocommerce' ), $posted [ 'receiver_email' ] ) );
2013-03-10 13:51:59 +00:00
2013-12-31 12:45:02 +00:00
exit ;
2013-03-10 13:51:59 +00:00
}
2012-05-26 16:25:07 +00:00
// Store PP Details
2013-12-31 12:53:55 +00:00
if ( ! empty ( $posted [ 'payer_email' ] ) ) {
2014-01-30 14:39:14 +00:00
update_post_meta ( $order -> id , 'Payer PayPal address' , wc_clean ( $posted [ 'payer_email' ] ) );
2013-12-31 12:53:55 +00:00
}
if ( ! empty ( $posted [ 'first_name' ] ) ) {
2014-01-30 14:39:14 +00:00
update_post_meta ( $order -> id , 'Payer first name' , wc_clean ( $posted [ 'first_name' ] ) );
2013-12-31 12:53:55 +00:00
}
if ( ! empty ( $posted [ 'last_name' ] ) ) {
2014-01-30 14:39:14 +00:00
update_post_meta ( $order -> id , 'Payer last name' , wc_clean ( $posted [ 'last_name' ] ) );
2013-12-31 12:53:55 +00:00
}
if ( ! empty ( $posted [ 'payment_type' ] ) ) {
2014-01-30 14:39:14 +00:00
update_post_meta ( $order -> id , 'Payment type' , wc_clean ( $posted [ 'payment_type' ] ) );
2013-12-31 12:53:55 +00:00
}
2013-12-31 12:45:02 +00:00
if ( $posted [ 'payment_status' ] == 'completed' ) {
$order -> add_order_note ( __ ( 'IPN payment completed' , 'woocommerce' ) );
2014-06-11 17:14:34 +00:00
$txn_id = ( ! empty ( $posted [ 'txn_id' ] ) ) ? wc_clean ( $posted [ 'txn_id' ] ) : '' ;
2014-06-11 14:36:55 +00:00
$order -> payment_complete ( $txn_id );
2013-12-31 12:45:02 +00:00
} else {
$order -> update_status ( 'on-hold' , sprintf ( __ ( 'Payment pending: %s' , 'woocommerce' ), $posted [ 'pending_reason' ] ) );
}
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-12-31 12:45:02 +00:00
$this -> log -> add ( 'paypal' , 'Payment complete.' );
2013-12-31 12:53:55 +00:00
}
2013-12-31 12:45:02 +00:00
break ;
case 'denied' :
case 'expired' :
case 'failed' :
case 'voided' :
// Order failed
$order -> update_status ( 'failed' , sprintf ( __ ( 'Payment %s via IPN.' , 'woocommerce' ), strtolower ( $posted [ 'payment_status' ] ) ) );
break ;
2013-12-31 12:53:55 +00:00
case 'refunded' :
2013-12-31 12:45:02 +00:00
// Only handle full refunds, not partial
if ( $order -> get_total () == ( $posted [ 'mc_gross' ] * - 1 ) ) {
// Mark order as refunded
$order -> update_status ( 'refunded' , sprintf ( __ ( 'Payment %s via IPN.' , 'woocommerce' ), strtolower ( $posted [ 'payment_status' ] ) ) );
2014-05-28 14:08:33 +00:00
$this -> send_ipn_email_notification (
2014-10-24 13:53:40 +00:00
sprintf ( __ ( 'Payment for order #%s refunded/reversed' , 'woocommerce' ), $order -> get_order_number () ),
2013-12-31 12:45:02 +00:00
sprintf ( __ ( 'Order %s has been marked as refunded - PayPal reason code: %s' , 'woocommerce' ), $order -> get_order_number (), $posted [ 'reason_code' ] )
2012-05-26 16:25:07 +00:00
);
}
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
break ;
2013-12-31 12:53:55 +00:00
case 'reversed' :
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
// Mark order as refunded
$order -> update_status ( 'on-hold' , sprintf ( __ ( 'Payment %s via IPN.' , 'woocommerce' ), strtolower ( $posted [ 'payment_status' ] ) ) );
2012-08-10 13:09:02 +00:00
2014-05-28 14:08:33 +00:00
$this -> send_ipn_email_notification (
2014-10-24 13:53:40 +00:00
sprintf ( __ ( 'Payment for order #%s reversed' , 'woocommerce' ), $order -> get_order_number () ),
2013-12-31 12:45:02 +00:00
sprintf ( __ ( 'Order %s has been marked on-hold due to a reversal - PayPal reason code: %s' , 'woocommerce' ), $order -> get_order_number (), $posted [ 'reason_code' ] )
2012-05-26 16:25:07 +00:00
);
2012-08-10 13:09:02 +00:00
2013-12-31 12:45:02 +00:00
break ;
2013-12-31 12:53:55 +00:00
case 'canceled_reversal' :
2014-05-28 14:08:33 +00:00
$this -> send_ipn_email_notification (
2014-10-24 13:53:40 +00:00
sprintf ( __ ( 'Reversal cancelled for order #%s' , 'woocommerce' ), $order -> get_order_number () ),
sprintf ( __ ( 'Order #%s has had a reversal cancelled. Please check the status of payment and update the order status accordingly.' , 'woocommerce' ), $order -> get_order_number () )
2013-08-15 10:19:26 +00:00
);
2013-12-31 12:45:02 +00:00
break ;
default :
// No action
break ;
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
exit ;
2013-12-31 12:45:02 +00:00
}
2014-05-15 13:35:16 +00:00
}
/**
* Send a notification to the user handling orders .
* @ param string $subject
* @ param string $message
*/
public function send_ipn_email_notification ( $subject , $message ) {
$new_order_settings = get_option ( 'woocommerce_new_order_settings' , array () );
$mailer = WC () -> mailer ();
$message = $mailer -> wrap_message ( $subject , $message );
2012-08-10 13:09:02 +00:00
2014-05-15 13:35:16 +00:00
$mailer -> send ( ! empty ( $new_order_settings [ 'recipient' ] ) ? $new_order_settings [ 'recipient' ] : get_option ( 'admin_email' ), $subject , $message );
2012-05-26 16:25:07 +00:00
}
2012-11-27 16:22:47 +00:00
2013-12-31 12:45:02 +00:00
/**
* Return handler
*
* Alternative to IPN
*/
public function pdt_return_handler () {
2013-08-19 11:28:29 +00:00
$posted = stripslashes_deep ( $_REQUEST );
2013-12-31 12:45:02 +00:00
if ( ! empty ( $this -> identity_token ) && ! empty ( $posted [ 'cm' ] ) ) {
2013-08-19 11:28:29 +00:00
2013-12-31 12:45:02 +00:00
$order = $this -> get_paypal_order ( $posted [ 'cm' ] );
2013-08-19 11:28:29 +00:00
2014-06-03 09:45:33 +00:00
if ( ! $order -> has_status ( 'pending' ) ) {
2013-12-03 14:03:25 +00:00
return false ;
2013-12-31 12:53:55 +00:00
}
2013-08-19 11:28:29 +00:00
2013-12-31 12:45:02 +00:00
$posted [ 'st' ] = strtolower ( $posted [ 'st' ] );
2013-08-19 11:28:29 +00:00
switch ( $posted [ 'st' ] ) {
2013-12-31 12:45:02 +00:00
case 'completed' :
2013-08-19 11:28:29 +00:00
2013-12-31 12:45:02 +00:00
// Validate transaction
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> testmode ) {
2013-08-19 11:28:29 +00:00
$paypal_adr = $this -> testurl ;
2013-12-31 12:53:55 +00:00
} else {
2013-08-19 11:28:29 +00:00
$paypal_adr = $this -> liveurl ;
2013-12-31 12:53:55 +00:00
}
2013-08-19 11:28:29 +00:00
2013-12-31 12:45:02 +00:00
$pdt = array (
'body' => array (
'cmd' => '_notify-synch' ,
'tx' => $posted [ 'tx' ],
'at' => $this -> identity_token
),
'sslverify' => false ,
'timeout' => 60 ,
'httpversion' => '1.1' ,
'user-agent' => 'WooCommerce/' . WC_VERSION
);
2013-08-19 11:28:29 +00:00
// Post back to get a response
2013-12-31 12:45:02 +00:00
$response = wp_remote_post ( $paypal_adr , $pdt );
2013-08-19 11:28:29 +00:00
2013-12-31 12:53:55 +00:00
if ( is_wp_error ( $response ) ) {
2013-12-31 12:45:02 +00:00
return false ;
2013-12-31 12:53:55 +00:00
}
2013-08-19 11:28:29 +00:00
2013-12-31 12:53:55 +00:00
if ( ! strpos ( $response [ 'body' ], " SUCCESS " ) === 0 ) {
2013-12-31 12:45:02 +00:00
return false ;
2013-12-31 12:53:55 +00:00
}
2013-08-19 11:28:29 +00:00
2013-12-31 12:45:02 +00:00
// Validate Amount
if ( $order -> get_total () != $posted [ 'amt' ] ) {
2013-08-19 11:28:29 +00:00
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-12-31 12:45:02 +00:00
$this -> log -> add ( 'paypal' , 'Payment error: Amounts do not match (amt ' . $posted [ 'amt' ] . ')' );
2013-12-31 12:53:55 +00:00
}
2013-08-19 11:28:29 +00:00
2013-12-31 12:45:02 +00:00
// Put this order on-hold for manual checking
$order -> update_status ( 'on-hold' , sprintf ( __ ( 'Validation error: PayPal amounts do not match (amt %s).' , 'woocommerce' ), $posted [ 'amt' ] ) );
return true ;
2013-08-19 11:28:29 +00:00
2013-12-31 12:45:02 +00:00
} else {
2013-08-19 11:28:29 +00:00
// Store PP Details
$order -> add_order_note ( __ ( 'PDT payment completed' , 'woocommerce' ) );
2014-06-11 17:14:34 +00:00
$txn_id = ( ! empty ( $posted [ 'tx' ] ) ) ? wc_clean ( $posted [ 'tx' ] ) : '' ;
2014-06-11 14:36:55 +00:00
$order -> payment_complete ( $txn_id );
2013-12-31 12:45:02 +00:00
return true ;
}
2013-08-19 11:28:29 +00:00
2013-12-31 12:45:02 +00:00
break ;
}
}
2013-12-03 14:03:25 +00:00
return false ;
2013-12-02 13:42:39 +00:00
}
2012-09-12 12:05:53 +00:00
2012-09-12 11:08:35 +00:00
/**
* get_paypal_order function .
2012-11-27 16:22:47 +00:00
*
2013-08-19 11:28:29 +00:00
* @ param string $custom
* @ param string $invoice
* @ return WC_Order object
2012-09-12 11:08:35 +00:00
*/
2013-08-19 11:28:29 +00:00
private function get_paypal_order ( $custom , $invoice = '' ) {
$custom = maybe_unserialize ( $custom );
2012-09-23 03:03:40 +00:00
2013-12-31 12:45:02 +00:00
// Backwards comp for IPN requests
if ( is_numeric ( $custom ) ) {
$order_id = ( int ) $custom ;
$order_key = $invoice ;
} elseif ( is_string ( $custom ) ) {
$order_id = ( int ) str_replace ( $this -> invoice_prefix , '' , $custom );
$order_key = $custom ;
} else {
list ( $order_id , $order_key ) = $custom ;
2012-09-23 03:03:40 +00:00
}
2012-09-12 11:08:35 +00:00
2014-08-15 12:29:21 +00:00
$order = wc_get_order ( $order_id );
2012-09-12 11:08:35 +00:00
2012-11-27 16:22:47 +00:00
if ( ! isset ( $order -> id ) ) {
2012-09-12 11:08:35 +00:00
// We have an invalid $order_id, probably because invoice_prefix has changed
2013-11-25 13:54:52 +00:00
$order_id = wc_get_order_id_by_order_key ( $order_key );
2014-08-15 12:29:21 +00:00
$order = wc_get_order ( $order_id );
2012-09-12 11:08:35 +00:00
}
2012-11-27 16:22:47 +00:00
2012-09-12 11:08:35 +00:00
// Validate key
if ( $order -> order_key !== $order_key ) {
2013-12-31 12:53:55 +00:00
if ( 'yes' == $this -> debug ) {
2013-12-31 12:45:02 +00:00
$this -> log -> add ( 'paypal' , 'Error: Order Key does not match invoice.' );
2013-12-31 12:53:55 +00:00
}
2013-12-31 12:45:02 +00:00
exit ;
}
2012-11-27 16:22:47 +00:00
2013-12-31 12:45:02 +00:00
return $order ;
2012-09-12 11:08:35 +00:00
}
2014-03-17 15:23:11 +00:00
/**
* Get the state to send to paypal
* @ param string $cc
* @ param string $state
* @ return string
*/
public function get_paypal_state ( $cc , $state ) {
if ( 'US' === $cc ) {
return $state ;
}
$states = WC () -> countries -> get_states ( $cc );
2014-05-28 14:08:33 +00:00
2014-03-17 15:23:11 +00:00
if ( isset ( $states [ $state ] ) ) {
return $states [ $state ];
}
return $state ;
}
2014-08-21 22:48:28 +00:00
/**
* Get the transaction URL .
*
2014-08-28 01:51:03 +00:00
* @ param WC_Order $order
2014-08-21 22:48:28 +00:00
*
* @ return string
*/
2014-08-28 01:51:03 +00:00
public function get_transaction_url ( $order ) {
if ( 'yes' == $this -> testmode ) {
$this -> view_transaction_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s' ;
} else {
$this -> view_transaction_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s' ;
2014-08-21 22:48:28 +00:00
}
2014-08-28 01:51:03 +00:00
return parent :: get_transaction_url ( $order );
2014-08-21 22:48:28 +00:00
}
2013-09-23 12:36:04 +00:00
}