laipower/wp-content/plugins/easy-digital-downloads/includes/gateways/amazon-payments.php

1175 lines
36 KiB
PHP

<?php
namespace PayWithAmazon;
/**
* Amazon Payments Gateway
*
* @package EDD
* @subpackage Gateways
* @copyright Copyright (c) 2015, Pippin's Pages, LLC
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
* @since 2.4
*/
// Exit if accessed directly
defined( 'ABSPATH' ) || exit;
final class EDD_Amazon_Payments {
private static $instance;
public $gateway_id = 'amazon';
public $client = null;
public $redirect_uri = null;
public $checkout_uri = null;
public $signin_redirect = null;
public $reference_id = null;
public $doing_ipn = false;
public $is_setup = null;
/**
* Get things going
*
* @access private
* @since 2.4
* @return void
*/
private function __construct() {
$this->reference_id = ! empty( $_REQUEST['amazon_reference_id'] )
? sanitize_text_field( $_REQUEST['amazon_reference_id'] )
: '';
// Run this separate so we can ditch as early as possible
$this->register();
if ( ! edd_is_gateway_active( $this->gateway_id ) ) {
return;
}
$this->config();
$this->includes();
$this->setup_client();
$this->filters();
$this->actions();
}
/**
* Retrieve current instance
*
* @access private
* @since 2.4
* @return EDD_Amazon_Payments instance
*/
public static function getInstance() {
if ( ! isset( self::$instance ) && ! ( self::$instance instanceof EDD_Amazon_Payments ) ) {
self::$instance = new EDD_Amazon_Payments;
}
return self::$instance;
}
/**
* Register the payment gateway
*
* @access private
* @since 2.4
* @return void
*/
private function register() {
add_filter( 'edd_payment_gateways', array( $this, 'register_gateway' ), 1, 1 );
}
/**
* Setup constant configuration for file paths
*
* @access private
* @since 2.4
* @return void
*/
private function config() {
if ( ! defined( 'EDD_AMAZON_CLASS_DIR' ) ) {
$path = trailingslashit( plugin_dir_path( EDD_PLUGIN_FILE ) ) . 'includes/gateways/libs/amazon';
define( 'EDD_AMAZON_CLASS_DIR', trailingslashit( $path ) );
}
}
/**
* Method to check if all the required settings have been filled out, allowing us to not output information without it.
*
* @since 2.7
* @return bool
*/
public function is_setup() {
if ( null !== $this->is_setup ) {
return $this->is_setup;
}
$required_items = array( 'merchant_id', 'client_id', 'access_key', 'secret_key' );
$current_values = array(
'merchant_id' => edd_get_option( 'amazon_seller_id', '' ),
'client_id' => edd_get_option( 'amazon_client_id', '' ),
'access_key' => edd_get_option( 'amazon_mws_access_key', '' ),
'secret_key' => edd_get_option( 'amazon_mws_secret_key', '' ),
);
$this->is_setup = true;
foreach ( $required_items as $key ) {
if ( empty( $current_values[ $key ] ) ) {
$this->is_setup = false;
break;
}
}
return $this->is_setup;
}
/**
* Load additional files
*
* @access private
* @since 2.4
* @return void
*/
private function includes() {
require_once EDD_AMAZON_CLASS_DIR . 'Client.php'; // Requires the other files itself
require_once EDD_AMAZON_CLASS_DIR . 'IpnHandler.php';
}
/**
* Add filters
*
* @since 2.4
* @return void
*/
private function filters() {
add_filter( 'edd_accepted_payment_icons', array( $this, 'register_payment_icon' ), 10, 1 );
add_filter( 'edd_show_gateways', array( $this, 'maybe_hide_gateway_select' ) );
// Since the Amazon Gateway loads scripts on page, it needs the scripts to load in the header.
add_filter( 'edd_load_scripts_in_footer', '__return_false' );
if ( is_admin() ) {
add_filter( 'edd_settings_sections_gateways', array( $this, 'register_gateway_section' ), 1, 1 );
add_filter( 'edd_settings_gateways', array( $this, 'register_gateway_settings' ), 1, 1 );
add_filter( 'edd_payment_details_transaction_id-' . $this->gateway_id, array( $this, 'link_transaction_id' ), 10, 2 );
}
}
/**
* Add actions
*
* @access private
* @since 2.4
* @return void
*/
private function actions() {
add_action( 'wp_enqueue_scripts', array( $this, 'print_client' ), 10 );
add_action( 'wp_enqueue_scripts', array( $this, 'load_scripts' ), 11 );
add_action( 'edd_pre_process_purchase', array( $this, 'check_config' ), 1 );
add_action( 'init', array( $this, 'capture_oauth' ), 9 );
add_action( 'init', array( $this, 'signin_redirect' ) );
add_action( 'edd_purchase_form_before_register_login', array( $this, 'login_form' ) );
add_action( 'edd_checkout_error_check', array( $this, 'checkout_errors' ), 10, 2 );
add_action( 'edd_gateway_amazon', array( $this, 'process_purchase' ) );
add_action( 'wp_ajax_edd_amazon_get_address', array( $this, 'ajax_get_address' ) );
add_action( 'wp_ajax_nopriv_edd_amazon_get_address', array( $this, 'ajax_get_address' ) );
add_action( 'edd_pre_process_purchase', array( $this, 'disable_address_requirement' ), 99999 );
add_action( 'init', array( $this, 'process_ipn' ) );
if ( empty( $this->reference_id ) ) {
return;
}
add_action( 'edd_amazon_cc_form', array( $this, 'wallet_form' ) );
}
/**
* Show an error message on checkout if Amazon is enabled but not setup.
*
* @since 2.7
*/
public function check_config() {
$is_enabled = edd_is_gateway_active( $this->gateway_id );
if ( ( ! $is_enabled || false === $this->is_setup() ) && 'amazon' == edd_get_chosen_gateway() ) {
edd_set_error( 'amazon_gateway_not_configured', __( 'There is an error with the Amazon Payments configuration.', 'easy-digital-downloads' ) );
}
}
/**
* Retrieve the client object
*
* @access private
* @since 2.4
* @return PayWithAmazon\Client
*/
private function get_client() {
if ( ! $this->is_setup() ) {
return false;
}
if ( ! is_null( $this->client ) ) {
return $this->client;
}
$this->setup_client();
return $this->client;
}
/**
* Setup the client object
*
* @access private
* @since 2.4
* @return void
*/
private function setup_client() {
if ( ! $this->is_setup() ) {
return;
}
$region = edd_get_shop_country();
if ( 'GB' === $region ) {
$region = 'UK';
}
$config = array(
'merchant_id' => edd_get_option( 'amazon_seller_id', '' ),
'client_id' => edd_get_option( 'amazon_client_id', '' ),
'access_key' => edd_get_option( 'amazon_mws_access_key', '' ),
'secret_key' => edd_get_option( 'amazon_mws_secret_key', '' ),
'region' => $region,
'sandbox' => edd_is_test_mode(),
);
$config = apply_filters( 'edd_amazon_client_config', $config );
$this->client = new Client( $config );
}
/**
* Register the gateway
*
* @since 2.4
* @param $gateways array
* @return array
*/
public function register_gateway( $gateways ) {
$default_amazon_info = array(
$this->gateway_id => array(
'admin_label' => __( 'Amazon', 'easy-digital-downloads' ),
'checkout_label' => __( 'Amazon', 'easy-digital-downloads' ),
'supports' => array(),
'icons' => array( 'amazon' ),
),
);
$default_amazon_info = apply_filters( 'edd_register_amazon_gateway', $default_amazon_info );
$gateways = array_merge( $gateways, $default_amazon_info );
return $gateways;
}
/**
* Register the payment icon
*
* @since 2.4
* @param array $payment_icons Array of payment icons
* @return array The array of icons with Amazon Added
*/
public function register_payment_icon( $payment_icons ) {
$payment_icons['amazon'] = 'Amazon';
return $payment_icons;
}
/**
* Hides payment gateway select options after return from Amazon
*
* @since 2.7.6
* @param bool $show Should gateway select be shown
* @return bool
*/
public function maybe_hide_gateway_select( $show ) {
if ( ! empty( $_REQUEST['payment-mode'] ) && 'amazon' == $_REQUEST['payment-mode'] && ! empty( $_REQUEST['amazon_reference_id'] ) && ! empty( $_REQUEST['state'] ) && 'authorized' == $_REQUEST['state'] ) {
$show = false;
}
return $show;
}
/**
* Register the payment gateways setting section
*
* @since 2.5
* @param array $gateway_sections Array of sections for the gateways tab
* @return array Added Amazon Payments into sub-sections
*/
public function register_gateway_section( $gateway_sections ) {
$gateway_sections['amazon'] = __( 'Amazon Payments', 'easy-digital-downloads' );
return $gateway_sections;
}
/**
* Register the gateway settings
*
* @since 2.4
* @param $gateway_settings array
* @return array
*/
public function register_gateway_settings( $gateway_settings ) {
$default_amazon_settings = array(
'amazon_register' => array(
'id' => 'amazon_register',
'name' => __( 'Register with Amazon', 'easy-digital-downloads' ),
'desc' => '<p><a href="' . esc_url( $this->get_registration_url() ) . '" class="button" target="_blank">' .
__( 'Connect Easy Digital Downloads to Amazon', 'easy-digital-downloads' ) .
'</a></p>' .
'<p class="description">' .
__( 'Once registration is complete, enter your API credentials below.', 'easy-digital-downloads' ) .
'</p>',
'type' => 'descriptive_text',
),
'amazon_seller_id' => array(
'id' => 'amazon_seller_id',
'name' => __( 'Seller ID', 'easy-digital-downloads' ),
'desc' => __( 'Found in the Integration settings. Also called a Merchant ID', 'easy-digital-downloads' ),
'type' => 'text',
'size' => 'regular',
),
'amazon_mws_access_key' => array(
'id' => 'amazon_mws_access_key',
'name' => __( 'MWS Access Key', 'easy-digital-downloads' ),
'desc' => __( 'Found on Seller Central in the MWS Keys section', 'easy-digital-downloads' ),
'type' => 'text',
'size' => 'regular',
),
'amazon_mws_secret_key' => array(
'id' => 'amazon_mws_secret_key',
'name' => __( 'MWS Secret Key', 'easy-digital-downloads' ),
'desc' => __( 'Found on Seller Central in the MWS Keys section', 'easy-digital-downloads' ),
'type' => 'text',
'size' => 'regular',
),
'amazon_client_id' => array(
'id' => 'amazon_client_id',
'name' => __( 'Client ID', 'easy-digital-downloads' ),
'desc' => __( 'The Amazon Client ID. Should look like `amzn1.application-oa2...`', 'easy-digital-downloads' ),
'type' => 'text',
'size' => 'regular',
),
'amazon_mws_callback_url' => array(
'id' => 'amazon_callback_url',
'name' => __( 'Amazon MWS Callback URL', 'easy-digital-downloads' ),
'desc' => __( 'The Return URL to provide in your MWS Application. Enter this under your Login and Pay &rarr; Web Settings', 'easy-digital-downloads' ),
'type' => 'text',
'size' => 'large',
'std' => $this->get_amazon_authenticate_redirect(),
'faux' => true,
),
'amazon_mws_ipn_url' => array(
'id' => 'amazon_ipn_url',
'name' => __( 'Amazon Merchant IPN URL', 'easy-digital-downloads' ),
'desc' => sprintf( __( 'The IPN URL to provide in your MWS account. Enter this under your <a href="%s">Integration Settings</a>', 'easy-digital-downloads' ), 'https://sellercentral.amazon.com/gp/pyop/seller/account/settings/user-settings-edit.html' ),
'type' => 'text',
'size' => 'large',
'std' => $this->get_amazon_ipn_url(),
'faux' => true,
),
);
$default_amazon_settings = apply_filters( 'edd_default_amazon_settings', $default_amazon_settings );
$gateway_settings['amazon'] = $default_amazon_settings;
return $gateway_settings;
}
/**
* Load javascript files and localized variables
*
* @since 2.4
* @return void
*/
public function load_scripts() {
if ( ! $this->is_setup() ) {
return;
}
if ( ! edd_is_checkout() ) {
return;
}
$test_mode = edd_is_test_mode();
$seller_id = edd_get_option( 'amazon_seller_id', '' );
$client_id = edd_get_option( 'amazon_client_id', '' );
$default_amazon_scope = array(
'profile',
'postal_code',
'payments:widget',
);
if ( edd_use_taxes() ) {
$default_amazon_scope[] = 'payments:shipping_address';
}
$default_amazon_button_settings = array(
'type' => 'PwA',
'color' => 'Gold',
'size' => 'medium',
'scope' => implode( ' ', $default_amazon_scope ),
'popup' => true,
);
$amazon_button_settings = apply_filters( 'edd_amazon_button_settings', $default_amazon_button_settings );
$base_url = '';
$sandbox = $test_mode ? 'sandbox/' : '';
switch ( edd_get_shop_country() ) {
case 'GB':
$base_url = 'https://static-eu.payments-amazon.com/OffAmazonPayments/uk/' . $sandbox . 'lpa/';
break;
case 'DE':
$base_url = 'https://static-eu.payments-amazon.com/OffAmazonPayments/de/' . $sandbox. 'lpa/';
break;
default:
$base_url = 'https://static-na.payments-amazon.com/OffAmazonPayments/us/' . $sandbox;
break;
}
if ( ! empty( $base_url ) ) {
$url = $base_url . 'js/Widgets.js?sellerId=' . $seller_id;
wp_enqueue_script( 'edd-amazon-widgets', $url, array( 'jquery' ), null, false );
wp_localize_script( 'edd-amazon-widgets', 'edd_amazon', apply_filters( 'edd_amazon_checkout_vars', array(
'sellerId' => $seller_id,
'clientId' => $client_id,
'referenceID' => $this->reference_id,
'buttonType' => $amazon_button_settings['type'],
'buttonColor' => $amazon_button_settings['color'],
'buttonSize' => $amazon_button_settings['size'],
'scope' => $amazon_button_settings['scope'],
'popup' => $amazon_button_settings['popup'],
'checkoutUri' => $this->get_amazon_checkout_uri(),
'redirectUri' => $this->get_amazon_authenticate_redirect(),
'signinUri' => $this->get_amazon_signin_redirect(),
) ) );
}
}
/**
* Print client ID in header
*
* @since 2.4
* @return void
*/
public function print_client() {
if ( ! $this->is_setup() ) {
return false;
}
if ( ! edd_is_checkout() ) {
return;
}
?>
<script>
window.onAmazonLoginReady = function() {
amazon.Login.setClientId(<?php echo json_encode( edd_get_option( 'amazon_client_id', '' ) ); ?>);
};
</script>
<?php
}
/**
* Capture authentication after returning from Amazon
*
* @since 2.4
* @return void
*/
public function capture_oauth() {
if ( ! isset( $_GET['edd-listener'] ) || $_GET['edd-listener'] !== 'amazon' ) {
return;
}
if ( ! isset( $_GET['state'] ) || $_GET['state'] !== 'return_auth' ) {
return;
}
if ( empty( $_GET['access_token'] ) || false === strpos( $_GET['access_token'], 'Atza' ) ) {
return;
}
try {
$profile = $this->client->getUserInfo( $_GET['access_token'] );
EDD()->session->set( 'amazon_access_token', $_GET['access_token'] );
EDD()->session->set( 'amazon_profile', $profile );
} catch( Exception $e ) {
wp_die( print_r( $e, true ) );
}
}
/**
* Set customer details after authentication
*
* @since 2.4
* @return void
*/
public function signin_redirect() {
if ( ! isset( $_GET['edd-listener'] ) || $_GET['edd-listener'] !== 'amazon' ) {
return;
}
if ( ! isset( $_GET['state'] ) || $_GET['state'] !== 'signed-in' ) {
return;
}
$profile = EDD()->session->get( 'amazon_profile' );
$reference = $_GET['amazon_reference_id'];
if ( ! is_user_logged_in() ) {
$user = get_user_by( 'email', $profile['email'] );
if ( $user ) {
edd_log_user_in( $user->ID, $user->user_login, '' );
$customer = array(
'first_name' => $user->first_name,
'last_name' => $user->last_name,
'email' => $user->user_email
);
} else {
$names = explode( ' ', $profile['name'], 2 );
$customer = array(
'first_name' => $names[0],
'last_name' => isset( $names[1] ) ? $names[1] : '',
'email' => $profile['email']
);
// Create a customer account if registration is not disabled
if ( 'none' !== edd_get_option( 'show_register_form' ) ) {
$args = array(
'user_email' => $profile['email'],
'user_login' => $profile['email'],
'display_name' => $profile['name'],
'first_name' => $customer['first_name'],
'last_name' => $customer['last_name'],
'user_pass' => wp_generate_password( 20 ),
);
$user_id = wp_insert_user( $args );
edd_log_user_in( $user_id, $args['user_login'], $args['user_pass'] );
}
}
EDD()->session->set( 'customer', $customer );
}
edd_redirect( edd_get_checkout_uri( array( 'payment-mode' => 'amazon', 'state' => 'authorized', 'amazon_reference_id' => urlencode( $reference ) ) ) );
}
/**
* Display the log in button
*
* @since 2.4
* @return void
*/
public function login_form() {
if ( ! $this->is_setup() ) {
return false;
}
if ( empty( $this->reference_id ) && 'amazon' == edd_get_chosen_gateway() ) :
remove_all_actions( 'edd_purchase_form_after_cc_form' );
remove_all_actions( 'edd_purchase_form_after_user_info' );
remove_all_actions( 'edd_purchase_form_register_fields' );
remove_all_actions( 'edd_purchase_form_login_fields' );
remove_all_actions( 'edd_register_fields_before' );
remove_all_actions( 'edd_cc_form' );
remove_all_actions( 'edd_checkout_form_top' );
ob_start(); ?>
<fieldset id="edd-amazon-login-fields" class="edd-amazon-fields">
<div id="edd-amazon-pay-button"></div>
<script type="text/javascript">
var authRequest;
OffAmazonPayments.Button('edd-amazon-pay-button', edd_amazon.sellerId, {
type: edd_amazon.buttonType,
color: edd_amazon.buttonColor,
size: edd_amazon.buttonSize,
authorization: function() {
loginOptions = {
scope: edd_amazon.scope,
popup: edd_amazon.popup
};
authRequest = amazon.Login.authorize( loginOptions, edd_amazon.redirectUri );
},
onSignIn: function( orderReference ) {
amazonOrderReferenceId = orderReference.getAmazonOrderReferenceId();
window.location = edd_amazon.signinUri + '&amazon_reference_id=' + amazonOrderReferenceId;
}, onError: function(error) {
jQuery('#edd_purchase_submit').prepend( '<div class="edd_errors"><p class="edd_error" id="edd_error_"' + error.getErrorCode() + '>' + error.getErrorMessage() + '</p></div>' );
}
});
</script>
</fieldset>
<?php
echo ob_get_clean();
endif;
}
/**
* Display the wallet and address forms
*
* @since 2.4
* @return void
*/
public function wallet_form() {
if ( ! $this->is_setup() ) {
return false;
}
$profile = EDD()->session->get( 'amazon_profile' );
remove_action( 'edd_purchase_form_after_cc_form', 'edd_checkout_tax_fields', 999 );
ob_start(); ?>
<fieldset id="edd_cc_fields" class="edd-amazon-fields">
<p class="edd-amazon-profile-wrapper">
<?php _e( 'Currently logged into Amazon as', 'easy-digital-downloads' ); ?>: <span class="edd-amazon-profile-name"><?php echo $profile['name']; ?></span>
<span class="edd-amazon-logout">(<a id="Logout"><?php _e( 'Logout', 'easy-digital-downloads' ); ?></a>)</span>
</p>
<?php if ( edd_use_taxes() ) : ?>
<div id="edd-amazon-address-box"></div>
<?php endif; ?>
<div id="edd-amazon-wallet-box"></div>
<script>
var edd_global_vars;
if ( '1' == edd_global_vars.taxes_enabled ) {
new OffAmazonPayments.Widgets.AddressBook({
sellerId: edd_amazon.sellerId,
amazonOrderReferenceId: edd_amazon.referenceID,
onOrderReferenceCreate: function(orderReference) {
orderReference.getAmazonOrderReferenceId();
},
onAddressSelect: function(orderReference) {
jQuery.ajax({
type: "POST",
data: {
action : 'edd_amazon_get_address',
reference_id : edd_amazon.referenceID
},
dataType: "json",
url: edd_global_vars.ajaxurl,
xhrFields: {
withCredentials: true
},
success: function (response) {
jQuery('#card_city').val( response.City );
jQuery('#card_address').val( response.AddressLine1 );
jQuery('#card_address_2').val( response.AddressLine2 );
jQuery('#card_zip').val( response.PostalCode );
jQuery('#billing_country').val( response.CountryCode );
jQuery('#card_state').val( response.StateOrRegion ).trigger( 'change' );
}
}).fail(function (response) {
if ( window.console && window.console.log ) {
console.log( response );
}
}).done(function (response) {
});
},
design: {
designMode: 'responsive'
},
onError: function(error) {
jQuery('#edd-amazon-address-box').hide();
jQuery('#edd_purchase_submit').prepend( '<div class="edd_errors"><p class="edd_error" id="edd_error_"' + error.getErrorCode() + '>' + error.getErrorMessage() + '</p></div>' );
}
}).bind("edd-amazon-address-box");
new OffAmazonPayments.Widgets.Wallet({
sellerId: edd_amazon.sellerId,
amazonOrderReferenceId: edd_amazon.referenceID,
design: {
designMode: 'responsive'
},
onPaymentSelect: function(orderReference) {
// Display your custom complete purchase button
},
onError: function(error) {
jQuery('#edd_purchase_submit').prepend( '<div class="edd_errors"><p class="edd_error" id="edd_error_"' + error.getErrorCode() + '>' + error.getErrorMessage() + '</p></div>' );
}
}).bind("edd-amazon-wallet-box");
} else {
new OffAmazonPayments.Widgets.Wallet({
sellerId: edd_amazon.sellerId,
design: {
designMode: 'responsive'
},
onOrderReferenceCreate: function(orderReference) {
jQuery( '#edd_amazon_reference_id' ).val( orderReference.getAmazonOrderReferenceId() );
},
onPaymentSelect: function(orderReference) {
// Display your custom complete purchase button
},
onError: function(error) {
jQuery('#edd_purchase_submit').prepend( '<div class="edd_errors"><p class="edd_error" id="edd_error_"' + error.getErrorCode() + '>' + error.getErrorMessage() + '</p></div>' );
}
}).bind("edd-amazon-wallet-box");
}
</script>
<div id="edd_cc_address">
<input type="hidden" name="edd_amazon_reference_id" id="edd_amazon_reference_id" value="<?php echo esc_attr( $this->reference_id ); ?>"/>
<input type="hidden" name="card_city" class="card_city" id="card_city" value=""/>
<input type="hidden" name="card_address" class="card_address" id="card_address" value=""/>
<input type="hidden" name="card_address_2" class="card_address_2" id="card_address_2" value=""/>
<input type="hidden" name="card_zip" class="card_zip" id="card_zip" value=""/>
<input type="hidden" name="card_state" class="card_state" id="card_state" value=""/>
<input type="hidden" name="billing_country" class="billing_country" id="billing_country" value=""/>
</div>
</fieldset>
<?php
echo ob_get_clean();
}
/**
* Retrieve the billing address via ajax
*
* @since 2.4
* @return void
*/
public function ajax_get_address() {
if ( ! $this->is_setup() ) {
return false;
}
if ( empty( $_POST['reference_id'] ) ) {
die( '-2' );
}
$request = $this->client->getOrderReferenceDetails( array(
'merchant_id' => edd_get_option( 'amazon_seller_id', '' ),
'amazon_order_reference_id' => $_POST['reference_id'],
'address_consent_token' => EDD()->session->get( 'amazon_access_token' )
) );
$address = array();
$data = new ResponseParser( $request->response );
$data = $data->toArray();
if ( isset( $data['GetOrderReferenceDetailsResult']['OrderReferenceDetails']['Destination']['PhysicalDestination'] ) ) {
$address = $data['GetOrderReferenceDetailsResult']['OrderReferenceDetails']['Destination']['PhysicalDestination'];
$address = wp_parse_args( $address, array( 'City', 'CountryCode', 'StateOrRegion', 'PostalCode', 'AddressLine1', 'AddressLine2' ) );
}
echo json_encode( $address ); exit;
}
/**
* Check for errors during checkout
*
* @since 2.4
* @param $valid_data Customer / product data from checkout
* @param $post_data $_POST
* @return void
*/
public function checkout_errors( $valid_data, $post_data ) {
// should validate that we have a reference ID here, perhaps even fire the API call here
if ( empty( $post_data['edd_amazon_reference_id'] ) ) {
edd_set_error( 'missing_reference_id', __( 'Missing Reference ID, please try again.', 'easy-digital-downloads' ) );
}
}
/**
* Process the purchase and create the charge in Amazon
*
* @since 2.4
* @param $purchase_data array Cart details
* @return void
*/
public function process_purchase( $purchase_data ) {
if ( empty( $purchase_data['post_data']['edd_amazon_reference_id'] ) ) {
edd_set_error( 'missing_reference_id', __( 'Missing Reference ID, please try again.', 'easy-digital-downloads' ) );
}
$errors = edd_get_errors();
if ( ! empty( $errors ) ) {
edd_send_back_to_checkout( '?payment-mode=amazon' );
}
$args = apply_filters( 'edd_amazon_charge_args', array(
'merchant_id' => edd_get_option( 'amazon_seller_id', '' ),
'amazon_reference_id' => $purchase_data['post_data']['edd_amazon_reference_id'],
'authorization_reference_id' => $purchase_data['purchase_key'],
'charge_amount' => $purchase_data['price'],
'currency_code' => edd_get_currency(),
'charge_note' => html_entity_decode( edd_get_purchase_summary( $purchase_data, false ) ),
'charge_order_id' => $purchase_data['purchase_key'],
'store_name' => remove_accents( wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ) ),
'transaction_timeout' => 0
), $purchase_data );
$args['platform_id'] = 'A3JST9YM1SX7LB';
$charge = $this->client->charge( $args );
if ( 200 == $charge->response['Status'] ) {
$charge = new ResponseParser( $charge->response );
$charge = $charge->toArray();
$status = $charge['AuthorizeResult']['AuthorizationDetails']['AuthorizationStatus']['State'];
if ( 'Declined' === $status ) {
$reason = $charge['AuthorizeResult']['AuthorizationDetails']['AuthorizationStatus']['ReasonCode'];
edd_set_error( 'payment_declined', sprintf( __( 'Your payment could not be authorized, please try a different payment method. Reason: %s', 'easy-digital-downloads' ), $reason ) );
edd_send_back_to_checkout( '?payment-mode=amazon&amazon_reference_id=' . $purchase_data['post_data']['edd_amazon_reference_id'] );
}
// Setup payment data to be recorded
$payment_data = array(
'price' => $purchase_data['price'],
'date' => $purchase_data['date'],
'user_email' => $purchase_data['user_email'],
'purchase_key' => $purchase_data['purchase_key'],
'currency' => edd_get_currency(),
'downloads' => $purchase_data['downloads'],
'user_info' => $purchase_data['user_info'],
'cart_details' => $purchase_data['cart_details'],
'gateway' => $this->gateway_id,
'status' => 'pending',
);
$payment_id = edd_insert_payment( $payment_data );
$authorization_id = $charge['AuthorizeResult']['AuthorizationDetails']['AmazonAuthorizationId'];
$capture_id = str_replace( '-A', '-C', $authorization_id );
$reference_id = sanitize_text_field( $_POST['edd_amazon_reference_id'] );
// Confirm the capture was completed
$capture = $this->client->getCaptureDetails( array(
'merchant_id' => edd_get_option( 'amazon_seller_id', '' ),
'amazon_capture_id' => $capture_id
) );
$capture = new ResponseParser( $capture->response );
$capture = $capture->toArray();
edd_update_payment_meta( $payment_id, '_edd_amazon_authorization_id', $authorization_id );
edd_update_payment_meta( $payment_id, '_edd_amazon_capture_id', $capture_id );
edd_set_payment_transaction_id( $payment_id, $reference_id, $purchase_data['price'] );
edd_update_payment_status( $payment_id, 'complete' );
// Empty the shopping cart
edd_empty_cart();
edd_send_to_success_page();
// Set an error
} else {
edd_set_error( 'amazon_error',sprintf( __( 'There was an issue processing your payment. Amazon error: %s', 'easy-digital-downloads' ), print_r( $charge, true ) ) );
edd_send_back_to_checkout( '?payment-mode=amazon&amazon_reference_id=' . $purchase_data['post_data']['edd_amazon_reference_id'] );
}
}
/**
* Retrieve the checkout URL for Amazon after authentication is complete
*
* @since 2.4
* @return string
*/
private function get_amazon_checkout_uri() {
if ( is_null( $this->checkout_uri ) ) {
$this->checkout_uri = esc_url_raw( add_query_arg( array( 'payment-mode' => 'amazon' ), edd_get_checkout_uri() ) );
}
return $this->checkout_uri;
}
/**
* Retrieve the return URL for Amazon after authentication on Amazon is complete
*
* @since 2.4
* @return string
*/
private function get_amazon_authenticate_redirect() {
if ( is_null( $this->redirect_uri ) ) {
$this->redirect_uri = esc_url_raw( add_query_arg( array( 'edd-listener' => 'amazon', 'state' => 'return_auth' ), edd_get_checkout_uri() ) );
}
return $this->redirect_uri;
}
/**
* Retrieve the URL to send customers too once sign-in is complete
*
* @since 2.4
* @return string
*/
private function get_amazon_signin_redirect() {
if ( is_null( $this->signin_redirect ) ) {
$this->signin_redirect = esc_url_raw( add_query_arg( array( 'edd-listener' => 'amazon', 'state' => 'signed-in' ), home_url() ) );
}
return $this->signin_redirect;
}
/**
* Retrieve the IPN URL for Amazon
*
* @since 2.4
* @return string
*/
private function get_amazon_ipn_url() {
return esc_url_raw( add_query_arg( array( 'edd-listener' => 'amazon' ), home_url( 'index.php' ) ) );
}
/**
* Removes the requirement for entering the billing address
*
* Address is pulled directly from Amazon
*
* @since 2.4
* @return void
*/
public function disable_address_requirement() {
if ( ! empty( $_POST['edd-gateway'] ) && $this->gateway_id == $_REQUEST['edd-gateway'] ) {
add_filter( 'edd_require_billing_address', '__return_false', 9999 );
}
}
/**
* Given a transaction ID, generate a link to the Amazon transaction ID details
*
* @since 2.4
* @param string $transaction_id The Transaction ID
* @param int $payment_id The payment ID for this transaction
* @return string A link to the PayPal transaction details
*/
public function link_transaction_id( $transaction_id, $payment_id ) {
$base_url = 'https://sellercentral.amazon.com/hz/me/pmd/payment-details?orderReferenceId=';
$transaction_url = '<a href="' . esc_url( $base_url . $transaction_id ) . '" target="_blank">' . esc_html( $transaction_id ) . '</a>';
return apply_filters( 'edd_' . $this->gateway_id . '_link_payment_details_transaction_id', $transaction_url );
}
/**
* Process IPN messages from Amazon
*
* @since 2.4
* @return void
*/
public function process_ipn() {
if ( ! isset( $_GET['edd-listener'] ) || $_GET['edd-listener'] !== 'amazon' ) {
return;
}
if ( isset( $_GET['state'] ) ) {
return;
}
// Get the IPN headers and Message body
$headers = getallheaders();
$body = file_get_contents( 'php://input' );
$this->doing_ipn = true;
try {
$ipn = new IpnHandler( $headers, $body );
$data = $ipn->toArray();
$seller_id = $data['SellerId'];
if ( $seller_id != edd_get_option( 'amazon_seller_id', '' ) ) {
wp_die( __( 'Invalid Amazon seller ID', 'easy-digital-downloads' ), __( 'IPN Error', 'easy-digital-downloads' ), array( 'response' => 401 ) );
}
switch( $data['NotificationType'] ) {
case 'OrderReferenceNotification' :
break;
case 'PaymentAuthorize' :
break;
case 'PaymentCapture' :
$key = $data['CaptureDetails']['CaptureReferenceId'];
$status = $data['CaptureDetails']['CaptureStatus']['State'];
if ( 'Declined' === $status ) {
$payment_id = edd_get_purchase_id_by_key( $key );
edd_update_payment_status( $payment_id, 'failed' );
edd_insert_payment_note( $payment_id, __( 'Capture declined in Amazon', 'easy-digital-downloads' ) );
}
break;
case 'PaymentRefund' :
$trans_id = substr( $data['RefundDetails']['AmazonRefundId'], 0, 19 );
$status = $data['RefundDetails']['RefundStatus']['State'];
if ( 'Completed' === $status ) {
$payment_id = edd_get_purchase_id_by_transaction_id( $trans_id );
edd_update_payment_status( $payment_id, 'refunded' );
edd_insert_payment_note( $payment_id, sprintf( __( 'Refund completed in Amazon. Refund ID: %s', 'easy-digital-downloads' ), $data['RefundDetails']['AmazonRefundId'] ) );
}
break;
}
} catch( Exception $e ) {
wp_die( $e->getErrorMessage(), __( 'IPN Error', 'easy-digital-downloads' ), array( 'response' => 401 ) );
}
}
/**
* Detect a refund action from EDD
*
* @deprecated 3.0 Due to issues with Amazon, refunds must be processed at the gateway.
* @since 2.4
* @param $payment_id int The ID number of the payment being refunded
* @param $new_status string The new status assigned to the payment
* @param $old_status string The previous status of the payment
* @return void
*/
public function process_refund( $payment_id, $new_status, $old_status ) {
_edd_deprecated_function( __METHOD__, '3.0' );
if ( 'complete' !== $old_status && 'revoked' !== $old_status ) {
return;
}
if ( 'refunded' !== $new_status ) {
return;
}
if ( ! empty( $this->doing_ipn ) ) {
return;
}
if ( 'amazon' !== edd_get_payment_gateway( $payment_id ) ) {
return;
}
$this->refund( $payment_id );
}
/**
* Refund a charge in Amazon
*
* @since 2.4
* @param $payment_id int The ID number of the payment being refunded
* @return string
*/
private function refund( $payment_id = 0 ) {
$refund = $this->client->refund( array(
'merchant_id' => edd_get_option( 'amazon_seller_id', '' ),
'amazon_capture_id' => edd_get_payment_meta( $payment_id, '_edd_amazon_capture_id', true ),
'refund_reference_id' => md5( edd_get_payment_key( $payment_id ) . '-refund' ),
'refund_amount' => edd_get_payment_amount( $payment_id ),
'currency_code' => edd_get_payment_currency_code( $payment_id ),
) );
if ( 200 == $refund->response['Status'] ) {
$refund = new ResponseParser( $refund->response );
$refund = $refund->toArray();
$reference_id = $refund['RefundResult']['RefundDetails']['RefundReferenceId'];
$status = $refund['RefundResult']['RefundDetails']['RefundStatus']['State'];
switch( $status ) {
case 'Declined' :
$note = __( 'Refund declined in Amazon. Refund ID: %s', 'easy-digital-downloads' );
break;
case 'Completed' :
$refund_id = $refund['RefundResult']['RefundDetails']['AmazonRefundId'];
$note = sprintf( __( 'Refund completed in Amazon. Refund ID: %s', 'easy-digital-downloads' ), $refund_id );
break;
case 'Pending' :
$note = sprintf( __( 'Refund initiated in Amazon. Reference ID: %s', 'easy-digital-downloads' ), $reference_id );
break;
}
edd_insert_payment_note( $payment_id, $note );
} else {
edd_insert_payment_note( $payment_id, __( 'Refund request failed in Amazon.', 'easy-digital-downloads' ) );
}
}
/**
* Retrieve the URL for connecting Amazon account to EDD
*
* @since 2.4
* @since 2.9.8 - Updated registration URL per Amazon Reps
* @return string
*/
private function get_registration_url() {
switch ( edd_get_shop_country() ) {
case 'GB':
$base_url = 'https://payments.amazon.co.uk/preregistration/lpa';
break;
case 'DE':
$base_url = 'https://payments.amazon.de/preregistration/lpa';
break;
default:
$base_url = 'https://sellercentral.amazon.com/hz/me/sp/signup';
break;
}
$query_args = array(
'registration_source' => 'SPPD',
'spId' => 'A3JST9YM1SX7LB',
);
return add_query_arg( $query_args, $base_url );
}
}