2012-05-26 16:25:07 +00:00
< ? php
/**
* 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-08-15 18:15:06 +00:00
* @ extends WC_Payment_Gateway
* @ version 1.6 . 4
* @ package WooCommerce / Classes / Payment
* @ author WooThemes
2012-05-26 16:25:07 +00:00
*/
2012-10-15 10:57:58 +00:00
if ( ! defined ( 'ABSPATH' ) ) exit ; // Exit if accessed directly
2012-05-26 16:25:07 +00:00
class WC_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
2012-08-15 18:15:06 +00:00
/**
* Constructor for the gateway .
*
* @ access public
* @ return void
*/
2012-08-10 13:09:02 +00:00
public function __construct () {
2012-05-26 16:25:07 +00:00
global $woocommerce ;
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
$this -> id = 'paypal' ;
2012-10-20 14:40:27 +00:00
$this -> icon = apply_filters ( 'woocommerce_paypal_icon' , $woocommerce -> plugin_url () . '/assets/images/icons/paypal.png' );
2012-05-26 16:25:07 +00:00
$this -> has_fields = false ;
$this -> liveurl = 'https://www.paypal.com/webscr' ;
$this -> testurl = 'https://www.sandbox.paypal.com/webscr' ;
2012-06-06 20:35:40 +00:00
$this -> method_title = __ ( 'PayPal' , 'woocommerce' );
2012-09-12 12:36:34 +00:00
$this -> notify_url = str_replace ( 'https:' , 'http:' , add_query_arg ( 'wc-api' , 'WC_Paypal' , home_url ( '/' ) ) );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Load the form fields.
$this -> init_form_fields ();
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Load the settings.
$this -> init_settings ();
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Define user set variables
$this -> title = $this -> settings [ 'title' ];
$this -> description = $this -> settings [ 'description' ];
$this -> email = $this -> settings [ 'email' ];
2012-08-10 13:09:02 +00:00
$this -> testmode = $this -> settings [ 'testmode' ];
2012-05-26 16:25:07 +00:00
$this -> send_shipping = $this -> settings [ 'send_shipping' ];
$this -> address_override = isset ( $this -> settings [ 'address_override' ] ) ? $this -> settings [ 'address_override' ] : 'no' ;
2012-08-10 13:09:02 +00:00
$this -> debug = $this -> settings [ 'debug' ];
2012-05-26 16:25:07 +00:00
$this -> form_submission_method = ( isset ( $this -> settings [ 'form_submission_method' ] ) && $this -> settings [ 'form_submission_method' ] == 'yes' ) ? true : false ;
$this -> page_style = ( isset ( $this -> settings [ 'page_style' ] ) ) ? $this -> settings [ 'page_style' ] : '' ;
2012-08-10 13:09:02 +00:00
$this -> invoice_prefix = ! empty ( $this -> settings [ 'invoice_prefix' ] ) ? $this -> settings [ 'invoice_prefix' ] : 'WC-' ;
2012-05-26 16:25:07 +00:00
// Logs
2012-12-27 10:20:04 +00:00
if ( $this -> debug == 'yes' )
$this -> log = $woocommerce -> logger ();
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' ) );
add_action ( 'woocommerce_receipt_paypal' , array ( $this , 'receipt_page' ) );
add_action ( 'woocommerce_update_options_payment_gateways' , array ( $this , 'process_admin_options' ) );
2012-11-27 16:22:47 +00:00
2012-09-12 12:36:34 +00:00
// Payment listener/API hook
2012-12-15 11:53:32 +00:00
add_action ( 'woocommerce_api_wc_paypal' , array ( $this , 'check_ipn_response' ) );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
if ( ! $this -> is_valid_for_use () ) $this -> enabled = false ;
2012-08-10 13:09:02 +00:00
}
2012-08-15 18:15:06 +00:00
/**
2012-05-26 16:25:07 +00:00
* Check if this gateway is enabled and available in the user ' s country
2012-08-15 18:15:06 +00:00
*
* @ access public
* @ return bool
2012-05-26 16:25:07 +00:00
*/
function is_valid_for_use () {
2012-10-20 14:40:27 +00:00
if ( ! in_array ( get_woocommerce_currency (), 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' ))) return false ;
2012-05-26 16:25:07 +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 () {
?>
2012-10-16 09:45:33 +00:00
< h3 >< ? php _e ( 'PayPal standard' , 'woocommerce' ); ?> </h3>
< p >< ? php _e ( 'PayPal standard works by sending the user to PayPal to enter their payment information.' , 'woocommerce' ); ?> </p>
2012-12-27 10:20:04 +00:00
< ? php if ( $this -> is_valid_for_use () ) : ?>
< table class = " form-table " >
< ? php
2012-05-26 16:25:07 +00:00
// Generate the HTML For the settings form.
2012-12-27 10:20:04 +00:00
$this -> generate_settings_html ();
?>
</ table ><!--/. form - table -->
< ? php else : ?>
< div class = " inline error " >< p >< strong >< ? php _e ( 'Gateway Disabled' , 'woocommerce' ); ?> </strong>: <?php _e( 'PayPal does not support your store currency.', 'woocommerce' ); ?></p></div>
< ? php
endif ;
2012-08-15 18:15:06 +00:00
}
2012-08-10 13:09:02 +00:00
2012-08-15 18:15:06 +00:00
/**
2012-05-26 16:25:07 +00:00
* Initialise Gateway Settings Form Fields
2012-08-15 18:15:06 +00:00
*
* @ access public
* @ return void
2012-05-26 16:25:07 +00:00
*/
function init_form_fields () {
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
$this -> form_fields = array (
'enabled' => array (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'Enable/Disable' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Enable PayPal standard' , 'woocommerce' ),
2012-05-26 16:25:07 +00:00
'default' => 'yes'
2012-08-10 13:09:02 +00:00
),
2012-05-26 16:25:07 +00:00
'title' => array (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'Title' , 'woocommerce' ),
'type' => 'text' ,
'description' => __ ( 'This controls the title which the user sees during checkout.' , 'woocommerce' ),
2012-05-26 16:25:07 +00:00
'default' => __ ( 'PayPal' , 'woocommerce' )
),
'description' => array (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'Description' , 'woocommerce' ),
'type' => 'textarea' ,
'description' => __ ( 'This controls the description which the user sees during checkout.' , 'woocommerce' ),
2012-10-16 14:46:21 +00:00
'default' => __ ( 'Pay via PayPal; you can pay with your credit card if you don\'t have a PayPal account' , 'woocommerce' )
2012-05-26 16:25:07 +00:00
),
'email' => array (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'PayPal Email' , 'woocommerce' ),
2012-11-20 17:32:50 +00:00
'type' => 'email' ,
2012-08-10 13:09:02 +00:00
'description' => __ ( 'Please enter your PayPal email address; this is needed in order to take payment.' , 'woocommerce' ),
2012-05-26 16:25:07 +00:00
'default' => ''
),
2012-08-10 13:09:02 +00:00
'invoice_prefix' => array (
'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 unqiue as PayPal will not allow orders with the same invoice number.' , 'woocommerce' ),
'default' => 'WC-'
),
2012-07-27 12:59:51 +00:00
'form_submission_method' => array (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'Submission method' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Use form submission method.' , 'woocommerce' ),
2012-07-27 12:59:51 +00:00
'description' => __ ( 'Enable this to post order data to PayPal via a form instead of using a redirect/querystring.' , 'woocommerce' ),
'default' => 'no'
2012-08-10 13:09:02 +00:00
),
2012-07-27 12:59:51 +00:00
'page_style' => array (
2012-08-10 13:09:02 +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' ),
2012-07-27 12:59:51 +00:00
'default' => ''
2012-08-10 13:09:02 +00:00
),
2012-07-27 12:59:51 +00:00
'shipping' => array (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'Shipping options' , 'woocommerce' ),
'type' => 'title' ,
2012-07-27 12:59:51 +00:00
'description' => '' ,
),
2012-05-26 16:25:07 +00:00
'send_shipping' => array (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'Shipping details' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Send shipping details to PayPal instead of billing.' , 'woocommerce' ),
2012-05-26 16:25:07 +00:00
'description' => '' ,
'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'
2012-08-10 13:09:02 +00:00
),
2012-05-26 16:25:07 +00:00
'address_override' => array (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'Address override' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Enable "address_override" to prevent address information from being changed.' , 'woocommerce' ),
2012-05-26 16:25:07 +00:00
'description' => __ ( 'PayPal verifies addresses therefore this setting can cause errors (we recommend keeping it disabled).' , 'woocommerce' ),
'default' => 'no'
2012-08-10 13:09:02 +00:00
),
2012-07-27 12:59:51 +00:00
'testing' => array (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'Gateway Testing' , 'woocommerce' ),
'type' => 'title' ,
2012-07-27 12:59:51 +00:00
'description' => '' ,
2012-05-26 16:25:07 +00:00
),
'testmode' => array (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'PayPal sandbox' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Enable PayPal sandbox' , 'woocommerce' ),
2012-05-26 16:25:07 +00:00
'default' => 'yes' ,
'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 (
2012-08-10 13:09:02 +00:00
'title' => __ ( 'Debug Log' , 'woocommerce' ),
'type' => 'checkbox' ,
'label' => __ ( 'Enable logging' , 'woocommerce' ),
2012-05-26 16:25:07 +00:00
'default' => 'no' ,
'description' => __ ( 'Log PayPal events, such as IPN requests, inside <code>woocommerce/logs/paypal.txt</code>' ),
)
);
2012-08-10 13:09:02 +00:00
2012-08-15 18:15:06 +00:00
}
2012-08-10 13:09:02 +00:00
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
*
* @ access public
* @ param mixed $order
* @ return array
*/
2012-05-26 16:25:07 +00:00
function get_paypal_args ( $order ) {
global $woocommerce ;
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
2012-11-27 16:22:47 +00:00
if ( $this -> debug == 'yes' )
2012-09-23 03:03:40 +00:00
$this -> log -> add ( 'paypal' , 'Generating payment form for order ' . $order -> get_order_number () . '. Notify URL: ' . $this -> notify_url );
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' ) ) ) {
$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 (
'cmd' => '_cart' ,
'business' => $this -> email ,
'no_note' => 1 ,
'currency_code' => get_woocommerce_currency (),
'charset' => 'UTF-8' ,
'rm' => is_ssl () ? 2 : 1 ,
'upload' => 1 ,
2012-08-21 12:49:07 +00:00
'return' => add_query_arg ( 'utm_nooverride' , '1' , $this -> get_return_url ( $order ) ),
2012-05-26 16:25:07 +00:00
'cancel_return' => $order -> get_cancel_order_url (),
'page_style' => $this -> page_style ,
2012-08-10 13:09:02 +00:00
// Order key + ID
2012-09-23 03:03:40 +00:00
'invoice' => $this -> invoice_prefix . ltrim ( $order -> get_order_number (), '#' ),
'custom' => serialize ( array ( $order_id , $order -> order_key ) ),
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// IPN
2012-09-12 12:36:34 +00:00
'notify_url' => $this -> notify_url ,
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Billing Address info
'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 ,
'state' => $order -> billing_state ,
'zip' => $order -> billing_postcode ,
'country' => $order -> billing_country ,
2012-08-10 13:09:02 +00:00
'email' => $order -> billing_email
),
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
if ( $this -> send_shipping == 'yes' ) {
$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 ;
$paypal_args [ 'state' ] = $order -> shipping_state ;
$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
2012-05-26 16:25:07 +00:00
// If prices include tax or have order discounts, send the whole order as a single item
2012-10-20 14:40:27 +00:00
if ( get_option ( 'woocommerce_prices_include_tax' ) == 'yes' || $order -> get_order_discount () > 0 ) {
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Discount
$paypal_args [ 'discount_amount_cart' ] = $order -> get_order_discount ();
2012-08-10 13:09:02 +00:00
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
2012-11-27 16:22:47 +00:00
if ( sizeof ( $order -> get_items () ) > 0 )
2012-10-20 14:40:27 +00:00
foreach ( $order -> get_items () as $item )
2012-11-27 16:22:47 +00:00
if ( $item [ 'qty' ] )
2012-10-20 14:40:27 +00:00
$item_names [] = $item [ 'name' ] . ' x ' . $item [ 'qty' ];
2012-08-10 13:09:02 +00:00
2012-10-20 14:40:27 +00:00
$paypal_args [ 'item_name_1' ] = sprintf ( __ ( 'Order %s' , 'woocommerce' ), $order -> get_order_number () ) . " - " . implode ( ', ' , $item_names );
2012-05-26 16:25:07 +00:00
$paypal_args [ 'quantity_1' ] = 1 ;
2012-10-20 14:40:27 +00:00
$paypal_args [ 'amount_1' ] = number_format ( $order -> get_total () - $order -> get_shipping () - $order -> get_shipping_tax () + $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
// b) paypal ignore anyhing over 5 digits, so 999.99 is the max
// $paypal_args['shipping_1'] = number_format( $order->get_shipping() + $order->get_shipping_tax() , 2, '.', '' );
2012-10-20 14:40:27 +00:00
if ( ( $order -> get_shipping () + $order -> get_shipping_tax () ) > 0 ) {
2012-07-27 12:59:51 +00:00
$paypal_args [ 'item_name_2' ] = __ ( 'Shipping via' , 'woocommerce' ) . ' ' . ucwords ( $order -> shipping_method_title );
2012-05-26 16:25:07 +00:00
$paypal_args [ 'quantity_2' ] = '1' ;
2012-07-27 12:59:51 +00:00
$paypal_args [ 'amount_2' ] = number_format ( $order -> get_shipping () + $order -> get_shipping_tax () , 2 , '.' , '' );
2012-10-20 14:40:27 +00:00
}
2012-08-10 13:09:02 +00:00
2012-10-20 14:40:27 +00:00
} else {
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Tax
$paypal_args [ 'tax_cart' ] = $order -> get_total_tax ();
// Cart Contents
$item_loop = 0 ;
2012-10-20 14:40:27 +00:00
if ( sizeof ( $order -> get_items () ) > 0 ) {
foreach ( $order -> get_items () as $item ) {
if ( $item [ 'qty' ] ) {
2012-11-27 16:22:47 +00:00
2012-10-20 14:40:27 +00:00
$item_loop ++ ;
2012-11-27 16:22:47 +00:00
2012-10-20 14:40:27 +00:00
$product = $order -> get_product_from_item ( $item );
2012-11-27 16:22:47 +00:00
2012-10-20 14:40:27 +00:00
$item_name = $item [ 'name' ];
2012-11-27 16:22:47 +00:00
2012-10-20 14:40:27 +00:00
$item_meta = new WC_Order_Item_Meta ( $item [ 'item_meta' ] );
if ( $meta = $item_meta -> display ( true , true ) )
$item_name .= ' ( ' . $meta . ' )' ;
2012-11-27 16:22:47 +00:00
2012-10-20 14:40:27 +00:00
$paypal_args [ 'item_name_' . $item_loop ] = $item_name ;
$paypal_args [ 'quantity_' . $item_loop ] = $item [ 'qty' ];
$paypal_args [ 'amount_' . $item_loop ] = $order -> get_item_total ( $item , false );
2012-11-27 16:22:47 +00:00
if ( $product -> get_sku () )
2012-10-20 14:40:27 +00:00
$paypal_args [ 'item_number_' . $item_loop ] = $product -> get_sku ();
}
}
}
2012-11-27 16:22:47 +00:00
2012-11-12 17:15:54 +00:00
// Fees
if ( sizeof ( $order -> get_fees () ) > 0 ) {
foreach ( $order -> get_fees () as $item ) {
$item_loop ++ ;
2012-11-27 16:22:47 +00:00
2012-11-12 17:15:54 +00:00
$paypal_args [ 'item_name_' . $item_loop ] = $item [ 'name' ];
$paypal_args [ 'quantity_' . $item_loop ] = 1 ;
$paypal_args [ 'amount_' . $item_loop ] = $item [ 'line_total' ];
}
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Shipping Cost item - paypal only allows shipping per item, we want to send shipping for the order
2012-10-20 14:40:27 +00:00
if ( $order -> get_shipping () > 0 ) {
2012-05-26 16:25:07 +00:00
$item_loop ++ ;
2012-10-20 14:40:27 +00:00
$paypal_args [ 'item_name_' . $item_loop ] = __ ( 'Shipping via' , 'woocommerce' ) . ' ' . ucwords ( $order -> shipping_method_title );
$paypal_args [ 'quantity_' . $item_loop ] = '1' ;
$paypal_args [ 'amount_' . $item_loop ] = number_format ( $order -> get_shipping (), 2 , '.' , '' );
}
2012-08-10 13:09:02 +00:00
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 = apply_filters ( 'woocommerce_paypal_args' , $paypal_args );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
return $paypal_args ;
}
2012-08-15 18:15:06 +00:00
/**
2012-05-26 16:25:07 +00:00
* Generate the paypal button link
2012-08-15 18:15:06 +00:00
*
* @ access public
* @ param mixed $order_id
* @ return string
*/
2012-05-26 16:25:07 +00:00
function generate_paypal_form ( $order_id ) {
global $woocommerce ;
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
$order = new WC_Order ( $order_id );
if ( $this -> testmode == 'yes' ) :
2012-08-10 13:09:02 +00:00
$paypal_adr = $this -> testurl . '?test_ipn=1&' ;
2012-05-26 16:25:07 +00:00
else :
2012-08-10 13:09:02 +00:00
$paypal_adr = $this -> liveurl . '?' ;
2012-05-26 16:25:07 +00:00
endif ;
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
$paypal_args = $this -> get_paypal_args ( $order );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
$paypal_args_array = array ();
foreach ( $paypal_args as $key => $value ) {
$paypal_args_array [] = '<input type="hidden" name="' . esc_attr ( $key ) . '" value="' . esc_attr ( $value ) . '" />' ;
}
2012-08-10 13:09:02 +00:00
2012-10-20 14:40:27 +00:00
$woocommerce -> add_inline_js ( '
2012-08-10 13:09:02 +00:00
jQuery ( " body " ) . block ({
2012-10-16 09:45:33 +00:00
message : " <img src= \" ' . esc_url( apply_filters( 'woocommerce_ajax_loader_url', $woocommerce->plugin_url () . '/assets/images/ajax-loader.gif' ) ) . ' \" alt= \" Redirecting… \" style= \" float:left; margin-right: 10px; \" />'.__( 'Thank you for your order. We are now redirecting you to PayPal to make payment.', 'woocommerce' ).' " ,
2012-08-10 13:09:02 +00:00
overlayCSS :
{
background : " #fff " ,
opacity : 0.6
2012-05-26 16:25:07 +00:00
},
2012-08-10 13:09:02 +00:00
css : {
padding : 20 ,
textAlign : " center " ,
color : " #555 " ,
border : " 3px solid #aaa " ,
backgroundColor : " #fff " ,
2012-05-26 16:25:07 +00:00
cursor : " wait " ,
lineHeight : " 32px "
2012-08-10 13:09:02 +00:00
}
2012-05-26 16:25:07 +00:00
});
jQuery ( " #submit_paypal_payment_form " ) . click ();
2012-10-20 14:40:27 +00:00
' );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
return '<form action="' . esc_url ( $paypal_adr ) . ' " method= " post " id= " paypal_payment_form " target= " _top " >
2012-10-20 14:40:27 +00:00
' . implode( ' ', $paypal_args_array) . '
2012-10-16 09:45:33 +00:00
< input type = " submit " class = " button-alt " id = " submit_paypal_payment_form " value = " '.__( 'Pay via PayPal', 'woocommerce' ).' " /> < a class = " button cancel " href = " '.esc_url( $order->get_cancel_order_url () ).' " > '.__( ' Cancel order & amp ; restore cart ', ' woocommerce ' ).' </ a >
2012-05-26 16:25:07 +00:00
</ form > ' ;
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-08-15 18:15:06 +00:00
/**
* Process the payment and return the result
*
* @ access public
* @ param int $order_id
* @ return array
*/
2012-05-26 16:25:07 +00:00
function process_payment ( $order_id ) {
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
$order = new WC_Order ( $order_id );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
if ( ! $this -> form_submission_method ) {
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
$paypal_args = $this -> get_paypal_args ( $order );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
$paypal_args = http_build_query ( $paypal_args , '' , '&' );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
if ( $this -> testmode == 'yes' ) :
2012-08-10 13:09:02 +00:00
$paypal_adr = $this -> testurl . '?test_ipn=1&' ;
2012-05-26 16:25:07 +00:00
else :
2012-08-10 13:09:02 +00:00
$paypal_adr = $this -> liveurl . '?' ;
2012-05-26 16:25:07 +00:00
endif ;
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
return array (
'result' => 'success' ,
'redirect' => $paypal_adr . $paypal_args
);
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
} else {
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
return array (
'result' => 'success' ,
2012-10-20 14:40:27 +00:00
'redirect' => add_query_arg ( 'order' , $order -> id , add_query_arg ( 'key' , $order -> order_key , get_permalink ( woocommerce_get_page_id ( 'pay' ))))
2012-05-26 16:25:07 +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
}
2012-08-10 13:09:02 +00:00
2012-08-15 18:15:06 +00:00
/**
* Output for the order received page .
*
* @ access public
* @ return void
*/
2012-05-26 16:25:07 +00:00
function receipt_page ( $order ) {
2012-08-10 13:09:02 +00:00
2012-10-16 09:45:33 +00:00
echo '<p>' . __ ( 'Thank you for your order, please click the button below to pay with PayPal.' , 'woocommerce' ) . '</p>' ;
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
echo $this -> generate_paypal_form ( $order );
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
/**
* Check PayPal IPN validity
**/
function check_ipn_request_is_valid () {
global $woocommerce ;
2012-08-10 13:09:02 +00:00
2012-11-27 16:22:47 +00:00
if ( $this -> debug == 'yes' )
2012-09-12 11:08:35 +00:00
$this -> log -> add ( 'paypal' , 'Checking IPN response is valid...' );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Get recieved values from post data
$received_values = ( array ) stripslashes_deep ( $_POST );
2012-12-26 21:45:53 +00:00
// Check email address to make sure that IPN response is not a spoof
2012-12-27 10:20:04 +00:00
if ( strcasecmp ( trim ( $received_values [ 'receiver_email' ] ), trim ( $this -> email ) ) != 0 ) {
if ( $this -> debug == 'yes' )
$this -> log -> add ( 'paypal' , " IPN Response is for another one: { $received_values [ 'receiver_email' ] } our email is { $this -> email } " );
2012-12-26 21:45:53 +00:00
return false ;
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Add cmd to the post array
$received_values [ 'cmd' ] = '_notify-validate' ;
// Send back post vars to paypal
2012-08-10 13:09:02 +00:00
$params = array (
2012-05-26 16:25:07 +00:00
'body' => $received_values ,
'sslverify' => false ,
'timeout' => 30 ,
'user-agent' => 'WooCommerce/' . $woocommerce -> version
);
// Get url
2012-09-12 11:08:35 +00:00
if ( $this -> testmode == 'yes' )
2012-08-10 13:09:02 +00:00
$paypal_adr = $this -> testurl ;
2012-09-12 11:08:35 +00:00
else
2012-08-10 13:09:02 +00:00
$paypal_adr = $this -> liveurl ;
2012-05-26 16:25:07 +00:00
// Post back to get a response
$response = wp_remote_post ( $paypal_adr , $params );
2012-08-10 13:09:02 +00:00
2012-11-27 16:22:47 +00:00
if ( $this -> debug == 'yes' )
2012-09-12 11:08:35 +00:00
$this -> log -> add ( 'paypal' , 'IPN Response: ' . print_r ( $response , true ) );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// check to see if the request was valid
2012-09-12 11:08:35 +00:00
if ( ! is_wp_error ( $response ) && $response [ 'response' ][ 'code' ] >= 200 && $response [ 'response' ][ 'code' ] < 300 && ( strcmp ( $response [ 'body' ], " VERIFIED " ) == 0 ) ) {
2012-11-27 16:22:47 +00:00
if ( $this -> debug == 'yes' )
2012-09-12 11:08:35 +00:00
$this -> log -> add ( 'paypal' , 'Received valid response from PayPal' );
2012-11-27 16:22:47 +00:00
2012-05-26 16:25:07 +00:00
return true ;
2012-08-10 13:09:02 +00:00
}
2012-09-12 11:08:35 +00:00
if ( $this -> debug == 'yes' ) {
2012-05-26 16:25:07 +00:00
$this -> log -> add ( 'paypal' , 'Received invalid response from PayPal' );
2012-09-12 11:08:35 +00:00
if ( is_wp_error ( $response ) )
2012-05-26 16:25:07 +00:00
$this -> log -> add ( 'paypal' , 'Error response: ' . $result -> get_error_message () );
2012-09-12 11:08:35 +00:00
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
return false ;
}
2012-08-10 13:09:02 +00:00
2012-08-15 18:15:06 +00:00
2012-05-26 16:25:07 +00:00
/**
* Check for PayPal IPN Response
2012-08-15 18:15:06 +00:00
*
* @ access public
* @ return void
*/
2012-05-26 16:25:07 +00:00
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
2012-09-12 12:36:34 +00:00
$_POST = stripslashes_deep ( $_POST );
2012-08-10 13:09:02 +00:00
2012-09-12 12:36:34 +00:00
if ( $this -> check_ipn_request_is_valid () ) {
2012-08-10 13:09:02 +00:00
2012-10-20 14:40:27 +00:00
header ( 'HTTP/1.1 200 OK' );
2012-08-10 13:09:02 +00:00
2012-09-12 12:36:34 +00:00
do_action ( " valid-paypal-standard-ipn-request " , $_POST );
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
2012-09-12 12:36:34 +00:00
wp_die ( " PayPal IPN Request Failure " );
2012-08-10 13:09:02 +00:00
2012-09-12 12:36:34 +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-08-15 18:15:06 +00:00
2012-05-26 16:25:07 +00:00
/**
* Successful Payment !
2012-08-15 18:15:06 +00:00
*
* @ access public
* @ param array $posted
* @ return void
*/
2012-05-26 16:25:07 +00:00
function successful_request ( $posted ) {
2012-07-17 14:36:08 +00:00
global $woocommerce ;
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Custom holds post ID
2012-09-12 11:08:35 +00:00
if ( ! empty ( $posted [ 'invoice' ] ) && ! empty ( $posted [ 'custom' ] ) ) {
2012-11-27 16:22:47 +00:00
2012-09-12 11:08:35 +00:00
$order = $this -> get_paypal_order ( $posted );
2012-11-27 16:22:47 +00:00
2012-09-12 11:08:35 +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
2012-09-12 11:08:35 +00:00
// Sandbox fix
2012-11-27 16:22:47 +00:00
if ( $posted [ 'test_ipn' ] == 1 && $posted [ 'payment_status' ] == 'pending' )
2012-09-12 11:08:35 +00:00
$posted [ 'payment_status' ] = 'completed' ;
2012-11-27 16:22:47 +00:00
if ( $this -> debug == 'yes' )
2012-09-12 11:08:35 +00:00
$this -> log -> add ( 'paypal' , 'Payment status: ' . $posted [ 'payment_status' ] );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// We are here so lets check status and do actions
2012-09-12 11:08:35 +00:00
switch ( $posted [ 'payment_status' ] ) {
2012-05-26 16:25:07 +00:00
case 'completed' :
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Check order not already completed
2012-09-12 11:08:35 +00:00
if ( $order -> status == 'completed' ) {
2012-11-27 16:22:47 +00:00
if ( $this -> debug == 'yes' )
2012-09-12 11:08:35 +00:00
$this -> log -> add ( 'paypal' , 'Aborting, Order #' . $order_id . ' is already complete.' );
2012-05-26 16:25:07 +00:00
exit ;
2012-09-12 11:08:35 +00:00
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Check valid txn_type
2012-09-12 11:08:35 +00:00
$accepted_types = array ( 'cart' , 'instant' , 'express_checkout' , 'web_accept' , 'masspay' , 'send_money' );
if ( ! in_array ( $posted [ 'txn_type' ], $accepted_types ) ) {
2012-11-27 16:22:47 +00:00
if ( $this -> debug == 'yes' )
2012-09-12 11:08:35 +00:00
$this -> log -> add ( 'paypal' , 'Aborting, Invalid type:' . $posted [ 'txn_type' ] );
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
2012-09-12 11:08:35 +00:00
// Validate Amount
2012-09-12 11:48:30 +00:00
if ( $order -> get_total () != $posted [ 'mc_gross' ] ) {
2012-11-27 16:22:47 +00:00
if ( $this -> debug == 'yes' )
2012-09-12 11:48:30 +00:00
$this -> log -> add ( 'paypal' , 'Payment error: Amounts do not match (gross ' . $posted [ 'mc_gross' ] . ')' );
2012-11-27 16:22:47 +00:00
2012-09-12 11:08:35 +00:00
// Put this order on-hold for manual checking
2012-09-12 12:09:54 +00:00
$order -> update_status ( 'on-hold' , sprintf ( __ ( 'Validation error: PayPal amounts do not match (gross %s).' , 'woocommerce' ), $posted [ 'mc_gross' ] ) );
2012-11-27 16:22:47 +00:00
2012-09-12 11:09:16 +00:00
exit ;
2012-11-27 16:22:47 +00:00
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Store PP Details
2012-08-10 13:09:02 +00:00
if ( ! empty ( $posted [ 'payer_email' ] ) )
update_post_meta ( $order_id , 'Payer PayPal address' , $posted [ 'payer_email' ] );
if ( ! empty ( $posted [ 'txn_id' ] ) )
update_post_meta ( $order_id , 'Transaction ID' , $posted [ 'txn_id' ] );
if ( ! empty ( $posted [ 'first_name' ] ) )
update_post_meta ( $order_id , 'Payer first name' , $posted [ 'first_name' ] );
if ( ! empty ( $posted [ 'last_name' ] ) )
update_post_meta ( $order_id , 'Payer last name' , $posted [ 'last_name' ] );
if ( ! empty ( $posted [ 'payment_type' ] ) )
update_post_meta ( $order_id , 'Payment type' , $posted [ 'payment_type' ] );
2012-05-26 16:25:07 +00:00
// Payment completed
2012-10-16 09:45:33 +00:00
$order -> add_order_note ( __ ( 'IPN payment completed' , 'woocommerce' ) );
2012-05-26 16:25:07 +00:00
$order -> payment_complete ();
2012-08-10 13:09:02 +00:00
2012-11-27 16:22:47 +00:00
if ( $this -> debug == 'yes' )
2012-09-12 11:08:35 +00:00
$this -> log -> add ( 'paypal' , 'Payment complete.' );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
break ;
case 'denied' :
case 'expired' :
case 'failed' :
case 'voided' :
// Order failed
2012-09-12 11:08:35 +00:00
$order -> update_status ( 'failed' , sprintf ( __ ( 'Payment %s via IPN.' , 'woocommerce' ), strtolower ( $posted [ 'payment_status' ] ) ) );
2012-05-26 16:25:07 +00:00
break ;
case " refunded " :
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Only handle full refunds, not partial
2012-09-12 11:08:35 +00:00
if ( $order -> get_total () == ( $posted [ 'mc_gross' ] * - 1 ) ) {
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Mark order as refunded
2012-09-12 11:08:35 +00:00
$order -> update_status ( 'refunded' , sprintf ( __ ( 'Payment %s via IPN.' , 'woocommerce' ), strtolower ( $posted [ 'payment_status' ] ) ) );
2012-08-10 13:09:02 +00:00
2012-07-17 14:36:08 +00:00
$mailer = $woocommerce -> mailer ();
2012-08-10 13:09:02 +00:00
2012-11-06 11:31:31 +00:00
$message = $mailer -> wrap_message (
2012-10-16 09:45:33 +00:00
__ ( 'Order refunded/reversed' , 'woocommerce' ),
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
2012-10-20 14:40:27 +00:00
$mailer -> send ( get_option ( 'woocommerce_new_order_email_recipient' ), sprintf ( __ ( 'Payment for order %s refunded/reversed' , 'woocommerce' ), $order -> get_order_number () ), $message );
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
break ;
case " reversed " :
case " chargeback " :
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
// Mark order as refunded
2012-10-16 09:45:33 +00:00
$order -> update_status ( 'refunded' , sprintf ( __ ( 'Payment %s via IPN.' , 'woocommerce' ), strtolower ( $posted [ 'payment_status' ] ) ) );
2012-08-10 13:09:02 +00:00
2012-07-17 14:36:08 +00:00
$mailer = $woocommerce -> mailer ();
2012-08-10 13:09:02 +00:00
2012-11-06 11:31:31 +00:00
$message = $mailer -> wrap_message (
2012-10-16 09:45:33 +00:00
__ ( 'Order refunded/reversed' , 'woocommerce' ),
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
2012-10-20 14:40:27 +00:00
$mailer -> send ( get_option ( 'woocommerce_new_order_email_recipient' ), sprintf ( __ ( 'Payment for order %s refunded/reversed' , 'woocommerce' ), $order -> get_order_number () ), $message );
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
break ;
2012-09-12 11:08:35 +00:00
default :
2012-05-26 16:25:07 +00:00
// No action
break ;
2012-09-12 11:08:35 +00:00
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
exit ;
}
2012-08-10 13:09:02 +00:00
2012-05-26 16:25:07 +00:00
}
2012-11-27 16:22:47 +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
*
2012-09-12 11:08:35 +00:00
* @ access public
2012-09-12 12:05:53 +00:00
* @ param mixed $posted
2012-09-12 11:08:35 +00:00
* @ return void
*/
2012-09-12 12:05:53 +00:00
function get_paypal_order ( $posted ) {
2012-09-23 03:03:40 +00:00
$custom = maybe_unserialize ( $posted [ 'custom' ] );
// Backwards comp for IPN requests
if ( is_numeric ( $custom ) ) {
$order_id = ( int ) $custom ;
$order_key = $posted [ 'invoice' ];
} elseif ( is_string ( $custom ) ) {
$order_id = ( int ) str_replace ( $this -> invoice_prefix , '' , $custom );
$order_key = $custom ;
2012-09-12 11:08:35 +00:00
} else {
2012-09-23 03:03:40 +00:00
list ( $order_id , $order_key ) = $custom ;
}
2012-09-12 11:08:35 +00:00
$order = new WC_Order ( $order_id );
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
$order_id = woocommerce_get_order_id_by_order_key ( $order_key );
$order = new WC_Order ( $order_id );
}
2012-11-27 16:22:47 +00:00
2012-09-12 11:08:35 +00:00
// Validate key
if ( $order -> order_key !== $order_key ) {
2012-11-27 16:22:47 +00:00
if ( $this -> debug == 'yes' )
2012-09-12 11:08:35 +00:00
$this -> log -> add ( 'paypal' , 'Error: Order Key does not match invoice.' );
exit ;
}
2012-11-27 16:22:47 +00:00
2012-09-12 11:08:35 +00:00
return $order ;
}
2012-05-26 16:25:07 +00:00
}
2012-08-15 18:15:06 +00:00
2012-05-26 16:25:07 +00:00
/**
* Add the gateway to WooCommerce
2012-08-15 18:15:06 +00:00
*
* @ access public
* @ param array $methods
* @ package WooCommerce / Classes / Payment
* @ return array
*/
2012-05-26 16:25:07 +00:00
function add_paypal_gateway ( $methods ) {
2012-08-15 18:15:06 +00:00
$methods [] = 'WC_Paypal' ;
return $methods ;
2012-05-26 16:25:07 +00:00
}
2012-08-15 18:15:06 +00:00
add_filter ( 'woocommerce_payment_gateways' , 'add_paypal_gateway' );