initial commit
This commit is contained in:
441
includes/gateways/bacs/class-wc-gateway-bacs.php
Normal file
441
includes/gateways/bacs/class-wc-gateway-bacs.php
Normal file
@ -0,0 +1,441 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WC_Gateway_BACS file.
|
||||
*
|
||||
* @package WooCommerce\Gateways
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Bank Transfer Payment Gateway.
|
||||
*
|
||||
* Provides a Bank Transfer Payment Gateway. Based on code by Mike Pepper.
|
||||
*
|
||||
* @class WC_Gateway_BACS
|
||||
* @extends WC_Payment_Gateway
|
||||
* @version 2.1.0
|
||||
* @package WooCommerce\Classes\Payment
|
||||
*/
|
||||
class WC_Gateway_BACS extends WC_Payment_Gateway {
|
||||
|
||||
/**
|
||||
* Array of locales
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $locale;
|
||||
|
||||
/**
|
||||
* Constructor for the gateway.
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
$this->id = 'bacs';
|
||||
$this->icon = apply_filters( 'woocommerce_bacs_icon', '' );
|
||||
$this->has_fields = false;
|
||||
$this->method_title = __( 'Direct bank transfer', 'woocommerce' );
|
||||
$this->method_description = __( 'Take payments in person via BACS. More commonly known as direct bank/wire transfer.', 'woocommerce' );
|
||||
|
||||
// Load the settings.
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
// Define user set variables.
|
||||
$this->title = $this->get_option( 'title' );
|
||||
$this->description = $this->get_option( 'description' );
|
||||
$this->instructions = $this->get_option( 'instructions' );
|
||||
|
||||
// BACS account fields shown on the thanks page and in emails.
|
||||
$this->account_details = get_option(
|
||||
'woocommerce_bacs_accounts',
|
||||
array(
|
||||
array(
|
||||
'account_name' => $this->get_option( 'account_name' ),
|
||||
'account_number' => $this->get_option( 'account_number' ),
|
||||
'sort_code' => $this->get_option( 'sort_code' ),
|
||||
'bank_name' => $this->get_option( 'bank_name' ),
|
||||
'iban' => $this->get_option( 'iban' ),
|
||||
'bic' => $this->get_option( 'bic' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Actions.
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'save_account_details' ) );
|
||||
add_action( 'woocommerce_thankyou_bacs', array( $this, 'thankyou_page' ) );
|
||||
|
||||
// Customer Emails.
|
||||
add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise Gateway Settings Form Fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable bank transfer', 'woocommerce' ),
|
||||
'default' => 'no',
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce' ),
|
||||
'type' => 'text',
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
|
||||
'default' => __( 'Direct bank transfer', 'woocommerce' ),
|
||||
'desc_tip' => true,
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce' ),
|
||||
'type' => 'textarea',
|
||||
'description' => __( 'Payment method description that the customer will see on your checkout.', 'woocommerce' ),
|
||||
'default' => __( 'Make your payment directly into our bank account. Please use your Order ID as the payment reference. Your order will not be shipped until the funds have cleared in our account.', 'woocommerce' ),
|
||||
'desc_tip' => true,
|
||||
),
|
||||
'instructions' => array(
|
||||
'title' => __( 'Instructions', 'woocommerce' ),
|
||||
'type' => 'textarea',
|
||||
'description' => __( 'Instructions that will be added to the thank you page and emails.', 'woocommerce' ),
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
),
|
||||
'account_details' => array(
|
||||
'type' => 'account_details',
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate account details html.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate_account_details_html() {
|
||||
|
||||
ob_start();
|
||||
|
||||
$country = WC()->countries->get_base_country();
|
||||
$locale = $this->get_country_locale();
|
||||
|
||||
// Get sortcode label in the $locale array and use appropriate one.
|
||||
$sortcode = isset( $locale[ $country ]['sortcode']['label'] ) ? $locale[ $country ]['sortcode']['label'] : __( 'Sort code', 'woocommerce' );
|
||||
|
||||
?>
|
||||
<tr valign="top">
|
||||
<th scope="row" class="titledesc"><?php esc_html_e( 'Account details:', 'woocommerce' ); ?></th>
|
||||
<td class="forminp" id="bacs_accounts">
|
||||
<div class="wc_input_table_wrapper">
|
||||
<table class="widefat wc_input_table sortable" cellspacing="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort"> </th>
|
||||
<th><?php esc_html_e( 'Account name', 'woocommerce' ); ?></th>
|
||||
<th><?php esc_html_e( 'Account number', 'woocommerce' ); ?></th>
|
||||
<th><?php esc_html_e( 'Bank name', 'woocommerce' ); ?></th>
|
||||
<th><?php echo esc_html( $sortcode ); ?></th>
|
||||
<th><?php esc_html_e( 'IBAN', 'woocommerce' ); ?></th>
|
||||
<th><?php esc_html_e( 'BIC / Swift', 'woocommerce' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="accounts">
|
||||
<?php
|
||||
$i = -1;
|
||||
if ( $this->account_details ) {
|
||||
foreach ( $this->account_details as $account ) {
|
||||
$i++;
|
||||
|
||||
echo '<tr class="account">
|
||||
<td class="sort"></td>
|
||||
<td><input type="text" value="' . esc_attr( wp_unslash( $account['account_name'] ) ) . '" name="bacs_account_name[' . esc_attr( $i ) . ']" /></td>
|
||||
<td><input type="text" value="' . esc_attr( $account['account_number'] ) . '" name="bacs_account_number[' . esc_attr( $i ) . ']" /></td>
|
||||
<td><input type="text" value="' . esc_attr( wp_unslash( $account['bank_name'] ) ) . '" name="bacs_bank_name[' . esc_attr( $i ) . ']" /></td>
|
||||
<td><input type="text" value="' . esc_attr( $account['sort_code'] ) . '" name="bacs_sort_code[' . esc_attr( $i ) . ']" /></td>
|
||||
<td><input type="text" value="' . esc_attr( $account['iban'] ) . '" name="bacs_iban[' . esc_attr( $i ) . ']" /></td>
|
||||
<td><input type="text" value="' . esc_attr( $account['bic'] ) . '" name="bacs_bic[' . esc_attr( $i ) . ']" /></td>
|
||||
</tr>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th colspan="7"><a href="#" class="add button"><?php esc_html_e( '+ Add account', 'woocommerce' ); ?></a> <a href="#" class="remove_rows button"><?php esc_html_e( 'Remove selected account(s)', 'woocommerce' ); ?></a></th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
jQuery(function() {
|
||||
jQuery('#bacs_accounts').on( 'click', 'a.add', function(){
|
||||
|
||||
var size = jQuery('#bacs_accounts').find('tbody .account').length;
|
||||
|
||||
jQuery('<tr class="account">\
|
||||
<td class="sort"></td>\
|
||||
<td><input type="text" name="bacs_account_name[' + size + ']" /></td>\
|
||||
<td><input type="text" name="bacs_account_number[' + size + ']" /></td>\
|
||||
<td><input type="text" name="bacs_bank_name[' + size + ']" /></td>\
|
||||
<td><input type="text" name="bacs_sort_code[' + size + ']" /></td>\
|
||||
<td><input type="text" name="bacs_iban[' + size + ']" /></td>\
|
||||
<td><input type="text" name="bacs_bic[' + size + ']" /></td>\
|
||||
</tr>').appendTo('#bacs_accounts table tbody');
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Save account details table.
|
||||
*/
|
||||
public function save_account_details() {
|
||||
|
||||
$accounts = array();
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce verification already handled in WC_Admin_Settings::save()
|
||||
if ( isset( $_POST['bacs_account_name'] ) && isset( $_POST['bacs_account_number'] ) && isset( $_POST['bacs_bank_name'] )
|
||||
&& isset( $_POST['bacs_sort_code'] ) && isset( $_POST['bacs_iban'] ) && isset( $_POST['bacs_bic'] ) ) {
|
||||
|
||||
$account_names = wc_clean( wp_unslash( $_POST['bacs_account_name'] ) );
|
||||
$account_numbers = wc_clean( wp_unslash( $_POST['bacs_account_number'] ) );
|
||||
$bank_names = wc_clean( wp_unslash( $_POST['bacs_bank_name'] ) );
|
||||
$sort_codes = wc_clean( wp_unslash( $_POST['bacs_sort_code'] ) );
|
||||
$ibans = wc_clean( wp_unslash( $_POST['bacs_iban'] ) );
|
||||
$bics = wc_clean( wp_unslash( $_POST['bacs_bic'] ) );
|
||||
|
||||
foreach ( $account_names as $i => $name ) {
|
||||
if ( ! isset( $account_names[ $i ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$accounts[] = array(
|
||||
'account_name' => $account_names[ $i ],
|
||||
'account_number' => $account_numbers[ $i ],
|
||||
'bank_name' => $bank_names[ $i ],
|
||||
'sort_code' => $sort_codes[ $i ],
|
||||
'iban' => $ibans[ $i ],
|
||||
'bic' => $bics[ $i ],
|
||||
);
|
||||
}
|
||||
}
|
||||
// phpcs:enable
|
||||
|
||||
update_option( 'woocommerce_bacs_accounts', $accounts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Output for the order received page.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
*/
|
||||
public function thankyou_page( $order_id ) {
|
||||
|
||||
if ( $this->instructions ) {
|
||||
echo wp_kses_post( wpautop( wptexturize( wp_kses_post( $this->instructions ) ) ) );
|
||||
}
|
||||
$this->bank_details( $order_id );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add content to the WC emails.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param bool $sent_to_admin Sent to admin.
|
||||
* @param bool $plain_text Email format: plain text or HTML.
|
||||
*/
|
||||
public function email_instructions( $order, $sent_to_admin, $plain_text = false ) {
|
||||
|
||||
if ( ! $sent_to_admin && 'bacs' === $order->get_payment_method() && $order->has_status( 'on-hold' ) ) {
|
||||
if ( $this->instructions ) {
|
||||
echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) . PHP_EOL );
|
||||
}
|
||||
$this->bank_details( $order->get_id() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bank details and place into a list format.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
*/
|
||||
private function bank_details( $order_id = '' ) {
|
||||
|
||||
if ( empty( $this->account_details ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get order and store in $order.
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
// Get the order country and country $locale.
|
||||
$country = $order->get_billing_country();
|
||||
$locale = $this->get_country_locale();
|
||||
|
||||
// Get sortcode label in the $locale array and use appropriate one.
|
||||
$sortcode = isset( $locale[ $country ]['sortcode']['label'] ) ? $locale[ $country ]['sortcode']['label'] : __( 'Sort code', 'woocommerce' );
|
||||
|
||||
$bacs_accounts = apply_filters( 'woocommerce_bacs_accounts', $this->account_details, $order_id );
|
||||
|
||||
if ( ! empty( $bacs_accounts ) ) {
|
||||
$account_html = '';
|
||||
$has_details = false;
|
||||
|
||||
foreach ( $bacs_accounts as $bacs_account ) {
|
||||
$bacs_account = (object) $bacs_account;
|
||||
|
||||
if ( $bacs_account->account_name ) {
|
||||
$account_html .= '<h3 class="wc-bacs-bank-details-account-name">' . wp_kses_post( wp_unslash( $bacs_account->account_name ) ) . ':</h3>' . PHP_EOL;
|
||||
}
|
||||
|
||||
$account_html .= '<ul class="wc-bacs-bank-details order_details bacs_details">' . PHP_EOL;
|
||||
|
||||
// BACS account fields shown on the thanks page and in emails.
|
||||
$account_fields = apply_filters(
|
||||
'woocommerce_bacs_account_fields',
|
||||
array(
|
||||
'bank_name' => array(
|
||||
'label' => __( 'Bank', 'woocommerce' ),
|
||||
'value' => $bacs_account->bank_name,
|
||||
),
|
||||
'account_number' => array(
|
||||
'label' => __( 'Account number', 'woocommerce' ),
|
||||
'value' => $bacs_account->account_number,
|
||||
),
|
||||
'sort_code' => array(
|
||||
'label' => $sortcode,
|
||||
'value' => $bacs_account->sort_code,
|
||||
),
|
||||
'iban' => array(
|
||||
'label' => __( 'IBAN', 'woocommerce' ),
|
||||
'value' => $bacs_account->iban,
|
||||
),
|
||||
'bic' => array(
|
||||
'label' => __( 'BIC', 'woocommerce' ),
|
||||
'value' => $bacs_account->bic,
|
||||
),
|
||||
),
|
||||
$order_id
|
||||
);
|
||||
|
||||
foreach ( $account_fields as $field_key => $field ) {
|
||||
if ( ! empty( $field['value'] ) ) {
|
||||
$account_html .= '<li class="' . esc_attr( $field_key ) . '">' . wp_kses_post( $field['label'] ) . ': <strong>' . wp_kses_post( wptexturize( $field['value'] ) ) . '</strong></li>' . PHP_EOL;
|
||||
$has_details = true;
|
||||
}
|
||||
}
|
||||
|
||||
$account_html .= '</ul>';
|
||||
}
|
||||
|
||||
if ( $has_details ) {
|
||||
echo '<section class="woocommerce-bacs-bank-details"><h2 class="wc-bacs-bank-details-heading">' . esc_html__( 'Our bank details', 'woocommerce' ) . '</h2>' . wp_kses_post( PHP_EOL . $account_html ) . '</section>';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the payment and return the result.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( $order->get_total() > 0 ) {
|
||||
// Mark as on-hold (we're awaiting the payment).
|
||||
$order->update_status( apply_filters( 'woocommerce_bacs_process_payment_order_status', 'on-hold', $order ), __( 'Awaiting BACS payment', 'woocommerce' ) );
|
||||
} else {
|
||||
$order->payment_complete();
|
||||
}
|
||||
|
||||
// Remove cart.
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
// Return thankyou redirect.
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $order ),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get country locale if localized.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_country_locale() {
|
||||
|
||||
if ( empty( $this->locale ) ) {
|
||||
|
||||
// Locale information to be used - only those that are not 'Sort Code'.
|
||||
$this->locale = apply_filters(
|
||||
'woocommerce_get_bacs_locale',
|
||||
array(
|
||||
'AU' => array(
|
||||
'sortcode' => array(
|
||||
'label' => __( 'BSB', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'CA' => array(
|
||||
'sortcode' => array(
|
||||
'label' => __( 'Bank transit number', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'IN' => array(
|
||||
'sortcode' => array(
|
||||
'label' => __( 'IFSC', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'IT' => array(
|
||||
'sortcode' => array(
|
||||
'label' => __( 'Branch sort', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'NZ' => array(
|
||||
'sortcode' => array(
|
||||
'label' => __( 'Bank code', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'SE' => array(
|
||||
'sortcode' => array(
|
||||
'label' => __( 'Bank code', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'US' => array(
|
||||
'sortcode' => array(
|
||||
'label' => __( 'Routing number', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'ZA' => array(
|
||||
'sortcode' => array(
|
||||
'label' => __( 'Branch code', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return $this->locale;
|
||||
|
||||
}
|
||||
}
|
||||
136
includes/gateways/cheque/class-wc-gateway-cheque.php
Normal file
136
includes/gateways/cheque/class-wc-gateway-cheque.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WC_Gateway_Cheque file.
|
||||
*
|
||||
* @package WooCommerce\Gateways
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Cheque Payment Gateway.
|
||||
*
|
||||
* Provides a Cheque Payment Gateway, mainly for testing purposes.
|
||||
*
|
||||
* @class WC_Gateway_Cheque
|
||||
* @extends WC_Payment_Gateway
|
||||
* @version 2.1.0
|
||||
* @package WooCommerce\Classes\Payment
|
||||
*/
|
||||
class WC_Gateway_Cheque extends WC_Payment_Gateway {
|
||||
|
||||
/**
|
||||
* Constructor for the gateway.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->id = 'cheque';
|
||||
$this->icon = apply_filters( 'woocommerce_cheque_icon', '' );
|
||||
$this->has_fields = false;
|
||||
$this->method_title = _x( 'Check payments', 'Check payment method', 'woocommerce' );
|
||||
$this->method_description = __( 'Take payments in person via checks. This offline gateway can also be useful to test purchases.', 'woocommerce' );
|
||||
|
||||
// Load the settings.
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
// Define user set variables.
|
||||
$this->title = $this->get_option( 'title' );
|
||||
$this->description = $this->get_option( 'description' );
|
||||
$this->instructions = $this->get_option( 'instructions' );
|
||||
|
||||
// Actions.
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
add_action( 'woocommerce_thankyou_cheque', array( $this, 'thankyou_page' ) );
|
||||
|
||||
// Customer Emails.
|
||||
add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise Gateway Settings Form Fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable check payments', 'woocommerce' ),
|
||||
'default' => 'no',
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce' ),
|
||||
'type' => 'text',
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
|
||||
'default' => _x( 'Check payments', 'Check payment method', 'woocommerce' ),
|
||||
'desc_tip' => true,
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce' ),
|
||||
'type' => 'textarea',
|
||||
'description' => __( 'Payment method description that the customer will see on your checkout.', 'woocommerce' ),
|
||||
'default' => __( 'Please send a check to Store Name, Store Street, Store Town, Store State / County, Store Postcode.', 'woocommerce' ),
|
||||
'desc_tip' => true,
|
||||
),
|
||||
'instructions' => array(
|
||||
'title' => __( 'Instructions', 'woocommerce' ),
|
||||
'type' => 'textarea',
|
||||
'description' => __( 'Instructions that will be added to the thank you page and emails.', 'woocommerce' ),
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output for the order received page.
|
||||
*/
|
||||
public function thankyou_page() {
|
||||
if ( $this->instructions ) {
|
||||
echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add content to the WC emails.
|
||||
*
|
||||
* @access public
|
||||
* @param WC_Order $order Order object.
|
||||
* @param bool $sent_to_admin Sent to admin.
|
||||
* @param bool $plain_text Email format: plain text or HTML.
|
||||
*/
|
||||
public function email_instructions( $order, $sent_to_admin, $plain_text = false ) {
|
||||
if ( $this->instructions && ! $sent_to_admin && 'cheque' === $order->get_payment_method() && $order->has_status( 'on-hold' ) ) {
|
||||
echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) . PHP_EOL );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the payment and return the result.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( $order->get_total() > 0 ) {
|
||||
// Mark as on-hold (we're awaiting the cheque).
|
||||
$order->update_status( apply_filters( 'woocommerce_cheque_process_payment_order_status', 'on-hold', $order ), _x( 'Awaiting check payment', 'Check payment method', 'woocommerce' ) );
|
||||
} else {
|
||||
$order->payment_complete();
|
||||
}
|
||||
|
||||
// Remove cart.
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
// Return thankyou redirect.
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $order ),
|
||||
);
|
||||
}
|
||||
}
|
||||
99
includes/gateways/class-wc-payment-gateway-cc.php
Normal file
99
includes/gateways/class-wc-payment-gateway-cc.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WC_Payment_Gateway_CC file.
|
||||
*
|
||||
* @package WooCommerce\Gateways
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Credit Card Payment Gateway
|
||||
*
|
||||
* @since 2.6.0
|
||||
* @package WooCommerce\Classes
|
||||
*/
|
||||
class WC_Payment_Gateway_CC extends WC_Payment_Gateway {
|
||||
|
||||
/**
|
||||
* Builds our payment fields area - including tokenization fields for logged
|
||||
* in users, and the actual payment fields.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public function payment_fields() {
|
||||
if ( $this->supports( 'tokenization' ) && is_checkout() ) {
|
||||
$this->tokenization_script();
|
||||
$this->saved_payment_methods();
|
||||
$this->form();
|
||||
$this->save_payment_method_checkbox();
|
||||
} else {
|
||||
$this->form();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output field name HTML
|
||||
*
|
||||
* Gateways which support tokenization do not require names - we don't want the data to post to the server.
|
||||
*
|
||||
* @since 2.6.0
|
||||
* @param string $name Field name.
|
||||
* @return string
|
||||
*/
|
||||
public function field_name( $name ) {
|
||||
return $this->supports( 'tokenization' ) ? '' : ' name="' . esc_attr( $this->id . '-' . $name ) . '" ';
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs fields for entering credit card information.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public function form() {
|
||||
wp_enqueue_script( 'wc-credit-card-form' );
|
||||
|
||||
$fields = array();
|
||||
|
||||
$cvc_field = '<p class="form-row form-row-last">
|
||||
<label for="' . esc_attr( $this->id ) . '-card-cvc">' . esc_html__( 'Card code', 'woocommerce' ) . ' <span class="required">*</span></label>
|
||||
<input id="' . esc_attr( $this->id ) . '-card-cvc" class="input-text wc-credit-card-form-card-cvc" inputmode="numeric" autocomplete="off" autocorrect="no" autocapitalize="no" spellcheck="no" type="tel" maxlength="4" placeholder="' . esc_attr__( 'CVC', 'woocommerce' ) . '" ' . $this->field_name( 'card-cvc' ) . ' style="width:100px" />
|
||||
</p>';
|
||||
|
||||
$default_fields = array(
|
||||
'card-number-field' => '<p class="form-row form-row-wide">
|
||||
<label for="' . esc_attr( $this->id ) . '-card-number">' . esc_html__( 'Card number', 'woocommerce' ) . ' <span class="required">*</span></label>
|
||||
<input id="' . esc_attr( $this->id ) . '-card-number" class="input-text wc-credit-card-form-card-number" inputmode="numeric" autocomplete="cc-number" autocorrect="no" autocapitalize="no" spellcheck="no" type="tel" placeholder="•••• •••• •••• ••••" ' . $this->field_name( 'card-number' ) . ' />
|
||||
</p>',
|
||||
'card-expiry-field' => '<p class="form-row form-row-first">
|
||||
<label for="' . esc_attr( $this->id ) . '-card-expiry">' . esc_html__( 'Expiry (MM/YY)', 'woocommerce' ) . ' <span class="required">*</span></label>
|
||||
<input id="' . esc_attr( $this->id ) . '-card-expiry" class="input-text wc-credit-card-form-card-expiry" inputmode="numeric" autocomplete="cc-exp" autocorrect="no" autocapitalize="no" spellcheck="no" type="tel" placeholder="' . esc_attr__( 'MM / YY', 'woocommerce' ) . '" ' . $this->field_name( 'card-expiry' ) . ' />
|
||||
</p>',
|
||||
);
|
||||
|
||||
if ( ! $this->supports( 'credit_card_form_cvc_on_saved_method' ) ) {
|
||||
$default_fields['card-cvc-field'] = $cvc_field;
|
||||
}
|
||||
|
||||
$fields = wp_parse_args( $fields, apply_filters( 'woocommerce_credit_card_form_fields', $default_fields, $this->id ) );
|
||||
?>
|
||||
|
||||
<fieldset id="wc-<?php echo esc_attr( $this->id ); ?>-cc-form" class='wc-credit-card-form wc-payment-form'>
|
||||
<?php do_action( 'woocommerce_credit_card_form_start', $this->id ); ?>
|
||||
<?php
|
||||
foreach ( $fields as $field ) {
|
||||
echo $field; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
?>
|
||||
<?php do_action( 'woocommerce_credit_card_form_end', $this->id ); ?>
|
||||
<div class="clear"></div>
|
||||
</fieldset>
|
||||
<?php
|
||||
|
||||
if ( $this->supports( 'credit_card_form_cvc_on_saved_method' ) ) {
|
||||
echo '<fieldset>' . $cvc_field . '</fieldset>'; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
}
|
||||
71
includes/gateways/class-wc-payment-gateway-echeck.php
Normal file
71
includes/gateways/class-wc-payment-gateway-echeck.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WC_Payment_Gateway_eCheck file.
|
||||
*
|
||||
* @package WooCommerce\Gateways
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for eCheck Payment Gateway
|
||||
*
|
||||
* @since 2.6.0
|
||||
* @package WooCommerce\Classes
|
||||
*/
|
||||
class WC_Payment_Gateway_ECheck extends WC_Payment_Gateway {
|
||||
|
||||
/**
|
||||
* Builds our payment fields area - including tokenization fields for logged
|
||||
* in users, and the actual payment fields.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public function payment_fields() {
|
||||
if ( $this->supports( 'tokenization' ) && is_checkout() ) {
|
||||
$this->tokenization_script();
|
||||
$this->saved_payment_methods();
|
||||
$this->form();
|
||||
$this->save_payment_method_checkbox();
|
||||
} else {
|
||||
$this->form();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs fields for entering eCheck information.
|
||||
*
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public function form() {
|
||||
$fields = array();
|
||||
|
||||
$default_fields = array(
|
||||
'routing-number' => '<p class="form-row form-row-first">
|
||||
<label for="' . esc_attr( $this->id ) . '-routing-number">' . esc_html__( 'Routing number', 'woocommerce' ) . ' <span class="required">*</span></label>
|
||||
<input id="' . esc_attr( $this->id ) . '-routing-number" class="input-text wc-echeck-form-routing-number" type="text" maxlength="9" autocomplete="off" placeholder="•••••••••" name="' . esc_attr( $this->id ) . '-routing-number" />
|
||||
</p>',
|
||||
'account-number' => '<p class="form-row form-row-wide">
|
||||
<label for="' . esc_attr( $this->id ) . '-account-number">' . esc_html__( 'Account number', 'woocommerce' ) . ' <span class="required">*</span></label>
|
||||
<input id="' . esc_attr( $this->id ) . '-account-number" class="input-text wc-echeck-form-account-number" type="text" autocomplete="off" name="' . esc_attr( $this->id ) . '-account-number" maxlength="17" />
|
||||
</p>',
|
||||
);
|
||||
|
||||
$fields = wp_parse_args( $fields, apply_filters( 'woocommerce_echeck_form_fields', $default_fields, $this->id ) );
|
||||
?>
|
||||
|
||||
<fieldset id="<?php echo esc_attr( $this->id ); ?>-cc-form" class='wc-echeck-form wc-payment-form'>
|
||||
<?php do_action( 'woocommerce_echeck_form_start', $this->id ); ?>
|
||||
<?php
|
||||
foreach ( $fields as $field ) {
|
||||
echo $field; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
?>
|
||||
<?php do_action( 'woocommerce_echeck_form_end', $this->id ); ?>
|
||||
<div class="clear"></div>
|
||||
</fieldset>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
378
includes/gateways/cod/class-wc-gateway-cod.php
Normal file
378
includes/gateways/cod/class-wc-gateway-cod.php
Normal file
@ -0,0 +1,378 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WC_Gateway_COD file.
|
||||
*
|
||||
* @package WooCommerce\Gateways
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Cash on Delivery Gateway.
|
||||
*
|
||||
* Provides a Cash on Delivery Payment Gateway.
|
||||
*
|
||||
* @class WC_Gateway_COD
|
||||
* @extends WC_Payment_Gateway
|
||||
* @version 2.1.0
|
||||
* @package WooCommerce\Classes\Payment
|
||||
*/
|
||||
class WC_Gateway_COD extends WC_Payment_Gateway {
|
||||
|
||||
/**
|
||||
* Constructor for the gateway.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Setup general properties.
|
||||
$this->setup_properties();
|
||||
|
||||
// Load the settings.
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
// Get settings.
|
||||
$this->title = $this->get_option( 'title' );
|
||||
$this->description = $this->get_option( 'description' );
|
||||
$this->instructions = $this->get_option( 'instructions' );
|
||||
$this->enable_for_methods = $this->get_option( 'enable_for_methods', array() );
|
||||
$this->enable_for_virtual = $this->get_option( 'enable_for_virtual', 'yes' ) === 'yes';
|
||||
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
add_action( 'woocommerce_thankyou_' . $this->id, array( $this, 'thankyou_page' ) );
|
||||
add_filter( 'woocommerce_payment_complete_order_status', array( $this, 'change_payment_complete_order_status' ), 10, 3 );
|
||||
|
||||
// Customer Emails.
|
||||
add_action( 'woocommerce_email_before_order_table', array( $this, 'email_instructions' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup general properties for the gateway.
|
||||
*/
|
||||
protected function setup_properties() {
|
||||
$this->id = 'cod';
|
||||
$this->icon = apply_filters( 'woocommerce_cod_icon', '' );
|
||||
$this->method_title = __( 'Cash on delivery', 'woocommerce' );
|
||||
$this->method_description = __( 'Have your customers pay with cash (or by other means) upon delivery.', 'woocommerce' );
|
||||
$this->has_fields = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise Gateway Settings Form Fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce' ),
|
||||
'label' => __( 'Enable cash on delivery', 'woocommerce' ),
|
||||
'type' => 'checkbox',
|
||||
'description' => '',
|
||||
'default' => 'no',
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce' ),
|
||||
'type' => 'text',
|
||||
'description' => __( 'Payment method description that the customer will see on your checkout.', 'woocommerce' ),
|
||||
'default' => __( 'Cash on delivery', 'woocommerce' ),
|
||||
'desc_tip' => true,
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce' ),
|
||||
'type' => 'textarea',
|
||||
'description' => __( 'Payment method description that the customer will see on your website.', 'woocommerce' ),
|
||||
'default' => __( 'Pay with cash upon delivery.', 'woocommerce' ),
|
||||
'desc_tip' => true,
|
||||
),
|
||||
'instructions' => array(
|
||||
'title' => __( 'Instructions', 'woocommerce' ),
|
||||
'type' => 'textarea',
|
||||
'description' => __( 'Instructions that will be added to the thank you page.', 'woocommerce' ),
|
||||
'default' => __( 'Pay with cash upon delivery.', 'woocommerce' ),
|
||||
'desc_tip' => true,
|
||||
),
|
||||
'enable_for_methods' => array(
|
||||
'title' => __( 'Enable for shipping methods', 'woocommerce' ),
|
||||
'type' => 'multiselect',
|
||||
'class' => 'wc-enhanced-select',
|
||||
'css' => 'width: 400px;',
|
||||
'default' => '',
|
||||
'description' => __( 'If COD is only available for certain methods, set it up here. Leave blank to enable for all methods.', 'woocommerce' ),
|
||||
'options' => $this->load_shipping_method_options(),
|
||||
'desc_tip' => true,
|
||||
'custom_attributes' => array(
|
||||
'data-placeholder' => __( 'Select shipping methods', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'enable_for_virtual' => array(
|
||||
'title' => __( 'Accept for virtual orders', 'woocommerce' ),
|
||||
'label' => __( 'Accept COD if the order is virtual', 'woocommerce' ),
|
||||
'type' => 'checkbox',
|
||||
'default' => 'yes',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check If The Gateway Is Available For Use.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_available() {
|
||||
$order = null;
|
||||
$needs_shipping = false;
|
||||
|
||||
// Test if shipping is needed first.
|
||||
if ( WC()->cart && WC()->cart->needs_shipping() ) {
|
||||
$needs_shipping = true;
|
||||
} elseif ( is_page( wc_get_page_id( 'checkout' ) ) && 0 < get_query_var( 'order-pay' ) ) {
|
||||
$order_id = absint( get_query_var( 'order-pay' ) );
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
// Test if order needs shipping.
|
||||
if ( $order && 0 < count( $order->get_items() ) ) {
|
||||
foreach ( $order->get_items() as $item ) {
|
||||
$_product = $item->get_product();
|
||||
if ( $_product && $_product->needs_shipping() ) {
|
||||
$needs_shipping = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$needs_shipping = apply_filters( 'woocommerce_cart_needs_shipping', $needs_shipping );
|
||||
|
||||
// Virtual order, with virtual disabled.
|
||||
if ( ! $this->enable_for_virtual && ! $needs_shipping ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only apply if all packages are being shipped via chosen method, or order is virtual.
|
||||
if ( ! empty( $this->enable_for_methods ) && $needs_shipping ) {
|
||||
$order_shipping_items = is_object( $order ) ? $order->get_shipping_methods() : false;
|
||||
$chosen_shipping_methods_session = WC()->session->get( 'chosen_shipping_methods' );
|
||||
|
||||
if ( $order_shipping_items ) {
|
||||
$canonical_rate_ids = $this->get_canonical_order_shipping_item_rate_ids( $order_shipping_items );
|
||||
} else {
|
||||
$canonical_rate_ids = $this->get_canonical_package_rate_ids( $chosen_shipping_methods_session );
|
||||
}
|
||||
|
||||
if ( ! count( $this->get_matching_rates( $canonical_rate_ids ) ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return parent::is_available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see whether or not the admin settings are being accessed by the current request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_accessing_settings() {
|
||||
if ( is_admin() ) {
|
||||
// phpcs:disable WordPress.Security.NonceVerification
|
||||
if ( ! isset( $_REQUEST['page'] ) || 'wc-settings' !== $_REQUEST['page'] ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! isset( $_REQUEST['tab'] ) || 'checkout' !== $_REQUEST['tab'] ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! isset( $_REQUEST['section'] ) || 'cod' !== $_REQUEST['section'] ) {
|
||||
return false;
|
||||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( Constants::is_true( 'REST_REQUEST' ) ) {
|
||||
global $wp;
|
||||
if ( isset( $wp->query_vars['rest_route'] ) && false !== strpos( $wp->query_vars['rest_route'], '/payment_gateways' ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all of the shipping method options for the enable_for_methods field.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function load_shipping_method_options() {
|
||||
// Since this is expensive, we only want to do it if we're actually on the settings page.
|
||||
if ( ! $this->is_accessing_settings() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$data_store = WC_Data_Store::load( 'shipping-zone' );
|
||||
$raw_zones = $data_store->get_zones();
|
||||
|
||||
foreach ( $raw_zones as $raw_zone ) {
|
||||
$zones[] = new WC_Shipping_Zone( $raw_zone );
|
||||
}
|
||||
|
||||
$zones[] = new WC_Shipping_Zone( 0 );
|
||||
|
||||
$options = array();
|
||||
foreach ( WC()->shipping()->load_shipping_methods() as $method ) {
|
||||
|
||||
$options[ $method->get_method_title() ] = array();
|
||||
|
||||
// Translators: %1$s shipping method name.
|
||||
$options[ $method->get_method_title() ][ $method->id ] = sprintf( __( 'Any "%1$s" method', 'woocommerce' ), $method->get_method_title() );
|
||||
|
||||
foreach ( $zones as $zone ) {
|
||||
|
||||
$shipping_method_instances = $zone->get_shipping_methods();
|
||||
|
||||
foreach ( $shipping_method_instances as $shipping_method_instance_id => $shipping_method_instance ) {
|
||||
|
||||
if ( $shipping_method_instance->id !== $method->id ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$option_id = $shipping_method_instance->get_rate_id();
|
||||
|
||||
// Translators: %1$s shipping method title, %2$s shipping method id.
|
||||
$option_instance_title = sprintf( __( '%1$s (#%2$s)', 'woocommerce' ), $shipping_method_instance->get_title(), $shipping_method_instance_id );
|
||||
|
||||
// Translators: %1$s zone name, %2$s shipping method instance name.
|
||||
$option_title = sprintf( __( '%1$s – %2$s', 'woocommerce' ), $zone->get_id() ? $zone->get_zone_name() : __( 'Other locations', 'woocommerce' ), $option_instance_title );
|
||||
|
||||
$options[ $method->get_method_title() ][ $option_id ] = $option_title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the chosen rate IDs generated by Shipping Methods to a canonical 'method_id:instance_id' format.
|
||||
*
|
||||
* @since 3.4.0
|
||||
*
|
||||
* @param array $order_shipping_items Array of WC_Order_Item_Shipping objects.
|
||||
* @return array $canonical_rate_ids Rate IDs in a canonical format.
|
||||
*/
|
||||
private function get_canonical_order_shipping_item_rate_ids( $order_shipping_items ) {
|
||||
|
||||
$canonical_rate_ids = array();
|
||||
|
||||
foreach ( $order_shipping_items as $order_shipping_item ) {
|
||||
$canonical_rate_ids[] = $order_shipping_item->get_method_id() . ':' . $order_shipping_item->get_instance_id();
|
||||
}
|
||||
|
||||
return $canonical_rate_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the chosen rate IDs generated by Shipping Methods to a canonical 'method_id:instance_id' format.
|
||||
*
|
||||
* @since 3.4.0
|
||||
*
|
||||
* @param array $chosen_package_rate_ids Rate IDs as generated by shipping methods. Can be anything if a shipping method doesn't honor WC conventions.
|
||||
* @return array $canonical_rate_ids Rate IDs in a canonical format.
|
||||
*/
|
||||
private function get_canonical_package_rate_ids( $chosen_package_rate_ids ) {
|
||||
|
||||
$shipping_packages = WC()->shipping()->get_packages();
|
||||
$canonical_rate_ids = array();
|
||||
|
||||
if ( ! empty( $chosen_package_rate_ids ) && is_array( $chosen_package_rate_ids ) ) {
|
||||
foreach ( $chosen_package_rate_ids as $package_key => $chosen_package_rate_id ) {
|
||||
if ( ! empty( $shipping_packages[ $package_key ]['rates'][ $chosen_package_rate_id ] ) ) {
|
||||
$chosen_rate = $shipping_packages[ $package_key ]['rates'][ $chosen_package_rate_id ];
|
||||
$canonical_rate_ids[] = $chosen_rate->get_method_id() . ':' . $chosen_rate->get_instance_id();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $canonical_rate_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a rate exists in an array of canonically-formatted rate IDs that activates this gateway.
|
||||
*
|
||||
* @since 3.4.0
|
||||
*
|
||||
* @param array $rate_ids Rate ids to check.
|
||||
* @return boolean
|
||||
*/
|
||||
private function get_matching_rates( $rate_ids ) {
|
||||
// First, match entries in 'method_id:instance_id' format. Then, match entries in 'method_id' format by stripping off the instance ID from the candidates.
|
||||
return array_unique( array_merge( array_intersect( $this->enable_for_methods, $rate_ids ), array_intersect( $this->enable_for_methods, array_unique( array_map( 'wc_get_string_before_colon', $rate_ids ) ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the payment and return the result.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( $order->get_total() > 0 ) {
|
||||
// Mark as processing or on-hold (payment won't be taken until delivery).
|
||||
$order->update_status( apply_filters( 'woocommerce_cod_process_payment_order_status', $order->has_downloadable_item() ? 'on-hold' : 'processing', $order ), __( 'Payment to be made upon delivery.', 'woocommerce' ) );
|
||||
} else {
|
||||
$order->payment_complete();
|
||||
}
|
||||
|
||||
// Remove cart.
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
// Return thankyou redirect.
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $order ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output for the order received page.
|
||||
*/
|
||||
public function thankyou_page() {
|
||||
if ( $this->instructions ) {
|
||||
echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change payment complete order status to completed for COD orders.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @param string $status Current order status.
|
||||
* @param int $order_id Order ID.
|
||||
* @param WC_Order|false $order Order object.
|
||||
* @return string
|
||||
*/
|
||||
public function change_payment_complete_order_status( $status, $order_id = 0, $order = false ) {
|
||||
if ( $order && 'cod' === $order->get_payment_method() ) {
|
||||
$status = 'completed';
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add content to the WC emails.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param bool $sent_to_admin Sent to admin.
|
||||
* @param bool $plain_text Email format: plain text or HTML.
|
||||
*/
|
||||
public function email_instructions( $order, $sent_to_admin, $plain_text = false ) {
|
||||
if ( $this->instructions && ! $sent_to_admin && $this->id === $order->get_payment_method() ) {
|
||||
echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) . PHP_EOL );
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
includes/gateways/paypal/assets/images/paypal.png
Normal file
BIN
includes/gateways/paypal/assets/images/paypal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
46
includes/gateways/paypal/assets/js/paypal-admin.js
Normal file
46
includes/gateways/paypal/assets/js/paypal-admin.js
Normal file
@ -0,0 +1,46 @@
|
||||
jQuery( function( $ ) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Object to handle PayPal admin functions.
|
||||
*/
|
||||
var wc_paypal_admin = {
|
||||
isTestMode: function() {
|
||||
return $( '#woocommerce_paypal_testmode' ).is( ':checked' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*/
|
||||
init: function() {
|
||||
$( document.body ).on( 'change', '#woocommerce_paypal_testmode', function() {
|
||||
var test_api_username = $( '#woocommerce_paypal_sandbox_api_username' ).parents( 'tr' ).eq( 0 ),
|
||||
test_api_password = $( '#woocommerce_paypal_sandbox_api_password' ).parents( 'tr' ).eq( 0 ),
|
||||
test_api_signature = $( '#woocommerce_paypal_sandbox_api_signature' ).parents( 'tr' ).eq( 0 ),
|
||||
live_api_username = $( '#woocommerce_paypal_api_username' ).parents( 'tr' ).eq( 0 ),
|
||||
live_api_password = $( '#woocommerce_paypal_api_password' ).parents( 'tr' ).eq( 0 ),
|
||||
live_api_signature = $( '#woocommerce_paypal_api_signature' ).parents( 'tr' ).eq( 0 );
|
||||
|
||||
if ( $( this ).is( ':checked' ) ) {
|
||||
test_api_username.show();
|
||||
test_api_password.show();
|
||||
test_api_signature.show();
|
||||
live_api_username.hide();
|
||||
live_api_password.hide();
|
||||
live_api_signature.hide();
|
||||
} else {
|
||||
test_api_username.hide();
|
||||
test_api_password.hide();
|
||||
test_api_signature.hide();
|
||||
live_api_username.show();
|
||||
live_api_password.show();
|
||||
live_api_signature.show();
|
||||
}
|
||||
} );
|
||||
|
||||
$( '#woocommerce_paypal_testmode' ).trigger( 'change' );
|
||||
}
|
||||
};
|
||||
|
||||
wc_paypal_admin.init();
|
||||
});
|
||||
1
includes/gateways/paypal/assets/js/paypal-admin.min.js
vendored
Normal file
1
includes/gateways/paypal/assets/js/paypal-admin.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
jQuery(function($){'use strict';var wc_paypal_admin={isTestMode:function(){return $('#woocommerce_paypal_testmode').is(':checked')},init:function(){$(document.body).on('change','#woocommerce_paypal_testmode',function(){var test_api_username=$('#woocommerce_paypal_sandbox_api_username').parents('tr').eq(0),test_api_password=$('#woocommerce_paypal_sandbox_api_password').parents('tr').eq(0),test_api_signature=$('#woocommerce_paypal_sandbox_api_signature').parents('tr').eq(0),live_api_username=$('#woocommerce_paypal_api_username').parents('tr').eq(0),live_api_password=$('#woocommerce_paypal_api_password').parents('tr').eq(0),live_api_signature=$('#woocommerce_paypal_api_signature').parents('tr').eq(0);if($(this).is(':checked')){test_api_username.show();test_api_password.show();test_api_signature.show();live_api_username.hide();live_api_password.hide();live_api_signature.hide()}else{test_api_username.hide();test_api_password.hide();test_api_signature.hide();live_api_username.show();live_api_password.show();live_api_signature.show()}});$('#woocommerce_paypal_testmode').change()}};wc_paypal_admin.init()})
|
||||
514
includes/gateways/paypal/class-wc-gateway-paypal.php
Normal file
514
includes/gateways/paypal/class-wc-gateway-paypal.php
Normal file
@ -0,0 +1,514 @@
|
||||
<?php
|
||||
/**
|
||||
* PayPal Standard Payment Gateway.
|
||||
*
|
||||
* Provides a PayPal Standard Payment Gateway.
|
||||
*
|
||||
* @class WC_Gateway_Paypal
|
||||
* @extends WC_Payment_Gateway
|
||||
* @version 2.3.0
|
||||
* @package WooCommerce\Classes\Payment
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC_Gateway_Paypal Class.
|
||||
*/
|
||||
class WC_Gateway_Paypal extends WC_Payment_Gateway {
|
||||
|
||||
/**
|
||||
* Whether or not logging is enabled
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $log_enabled = false;
|
||||
|
||||
/**
|
||||
* Logger instance
|
||||
*
|
||||
* @var WC_Logger
|
||||
*/
|
||||
public static $log = false;
|
||||
|
||||
/**
|
||||
* Constructor for the gateway.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->id = 'paypal';
|
||||
$this->has_fields = false;
|
||||
$this->order_button_text = __( 'Proceed to PayPal', 'woocommerce' );
|
||||
$this->method_title = __( 'PayPal Standard', 'woocommerce' );
|
||||
/* translators: %s: Link to WC system status page */
|
||||
$this->method_description = __( 'PayPal Standard redirects customers to PayPal to enter their payment information.', 'woocommerce' );
|
||||
$this->supports = array(
|
||||
'products',
|
||||
'refunds',
|
||||
);
|
||||
|
||||
// Load the settings.
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
// Define user set variables.
|
||||
$this->title = $this->get_option( 'title' );
|
||||
$this->description = $this->get_option( 'description' );
|
||||
$this->testmode = 'yes' === $this->get_option( 'testmode', 'no' );
|
||||
$this->debug = 'yes' === $this->get_option( 'debug', 'no' );
|
||||
$this->email = $this->get_option( 'email' );
|
||||
$this->receiver_email = $this->get_option( 'receiver_email', $this->email );
|
||||
$this->identity_token = $this->get_option( 'identity_token' );
|
||||
self::$log_enabled = $this->debug;
|
||||
|
||||
if ( $this->testmode ) {
|
||||
/* translators: %s: Link to PayPal sandbox testing guide page */
|
||||
$this->description .= ' ' . sprintf( __( 'SANDBOX ENABLED. You can use sandbox testing accounts only. See the <a href="%s">PayPal Sandbox Testing Guide</a> for more details.', 'woocommerce' ), 'https://developer.paypal.com/docs/classic/lifecycle/ug_sandbox/' );
|
||||
$this->description = trim( $this->description );
|
||||
}
|
||||
|
||||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
add_action( 'woocommerce_order_status_processing', array( $this, 'capture_payment' ) );
|
||||
add_action( 'woocommerce_order_status_completed', array( $this, 'capture_payment' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
|
||||
|
||||
if ( ! $this->is_valid_for_use() ) {
|
||||
$this->enabled = 'no';
|
||||
} else {
|
||||
include_once dirname( __FILE__ ) . '/includes/class-wc-gateway-paypal-ipn-handler.php';
|
||||
new WC_Gateway_Paypal_IPN_Handler( $this->testmode, $this->receiver_email );
|
||||
|
||||
if ( $this->identity_token ) {
|
||||
include_once dirname( __FILE__ ) . '/includes/class-wc-gateway-paypal-pdt-handler.php';
|
||||
new WC_Gateway_Paypal_PDT_Handler( $this->testmode, $this->identity_token );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 'yes' === $this->enabled ) {
|
||||
add_filter( 'woocommerce_thankyou_order_received_text', array( $this, 'order_received_text' ), 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not this gateway still requires setup to function.
|
||||
*
|
||||
* When this gateway is toggled on via AJAX, if this returns true a
|
||||
* redirect will occur to the settings page instead.
|
||||
*
|
||||
* @since 3.4.0
|
||||
* @return bool
|
||||
*/
|
||||
public function needs_setup() {
|
||||
return ! is_email( $this->email );
|
||||
}
|
||||
|
||||
/**
|
||||
* Logging method.
|
||||
*
|
||||
* @param string $message Log message.
|
||||
* @param string $level Optional. Default 'info'. Possible values:
|
||||
* emergency|alert|critical|error|warning|notice|info|debug.
|
||||
*/
|
||||
public static function log( $message, $level = 'info' ) {
|
||||
if ( self::$log_enabled ) {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = wc_get_logger();
|
||||
}
|
||||
self::$log->log( $level, $message, array( 'source' => 'paypal' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and saves options.
|
||||
* If there is an error thrown, will continue to save and validate fields, but will leave the erroring field out.
|
||||
*
|
||||
* @return bool was anything saved?
|
||||
*/
|
||||
public function process_admin_options() {
|
||||
$saved = parent::process_admin_options();
|
||||
|
||||
// Maybe clear logs.
|
||||
if ( 'yes' !== $this->get_option( 'debug', 'no' ) ) {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = wc_get_logger();
|
||||
}
|
||||
self::$log->clear( 'paypal' );
|
||||
}
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get gateway icon.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_icon() {
|
||||
// We need a base country for the link to work, bail if in the unlikely event no country is set.
|
||||
$base_country = WC()->countries->get_base_country();
|
||||
if ( empty( $base_country ) ) {
|
||||
return '';
|
||||
}
|
||||
$icon_html = '';
|
||||
$icon = (array) $this->get_icon_image( $base_country );
|
||||
|
||||
foreach ( $icon as $i ) {
|
||||
$icon_html .= '<img src="' . esc_attr( $i ) . '" alt="' . esc_attr__( 'PayPal acceptance mark', 'woocommerce' ) . '" />';
|
||||
}
|
||||
|
||||
$icon_html .= 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;">' . esc_attr__( 'What is PayPal?', 'woocommerce' ) . '</a>', esc_url( $this->get_icon_url( $base_country ) ) );
|
||||
|
||||
return apply_filters( 'woocommerce_gateway_icon', $icon_html, $this->id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the link for an icon based on country.
|
||||
*
|
||||
* @param string $country Country two letter code.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_icon_url( $country ) {
|
||||
$url = 'https://www.paypal.com/' . strtolower( $country );
|
||||
$home_counties = array( 'BE', 'CZ', 'DK', 'HU', 'IT', 'JP', 'NL', 'NO', 'ES', 'SE', 'TR', 'IN' );
|
||||
$countries = array( 'DZ', 'AU', 'BH', 'BQ', 'BW', 'CA', 'CN', 'CW', 'FI', 'FR', 'DE', 'GR', 'HK', 'ID', 'JO', 'KE', 'KW', 'LU', 'MY', 'MA', 'OM', 'PH', 'PL', 'PT', 'QA', 'IE', 'RU', 'BL', 'SX', 'MF', 'SA', 'SG', 'SK', 'KR', 'SS', 'TW', 'TH', 'AE', 'GB', 'US', 'VN' );
|
||||
|
||||
if ( in_array( $country, $home_counties, true ) ) {
|
||||
return $url . '/webapps/mpp/home';
|
||||
} elseif ( in_array( $country, $countries, true ) ) {
|
||||
return $url . '/webapps/mpp/paypal-popup';
|
||||
} else {
|
||||
return $url . '/cgi-bin/webscr?cmd=xpt/Marketing/general/WIPaypal-outside';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PayPal images for a country.
|
||||
*
|
||||
* @param string $country Country code.
|
||||
* @return array of image URLs
|
||||
*/
|
||||
protected function get_icon_image( $country ) {
|
||||
switch ( $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',
|
||||
);
|
||||
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;
|
||||
case 'JP':
|
||||
$icon = 'https://www.paypal.com/ja_JP/JP/i/bnr/horizontal_solution_4_jcb.gif';
|
||||
break;
|
||||
case 'IN':
|
||||
$icon = 'https://www.paypalobjects.com/webstatic/mktg/logo/AM_mc_vs_dc_ae.jpg';
|
||||
break;
|
||||
default:
|
||||
$icon = WC_HTTPS::force_https_url( WC()->plugin_url() . '/includes/gateways/paypal/assets/images/paypal.png' );
|
||||
break;
|
||||
}
|
||||
return apply_filters( 'woocommerce_paypal_icon', $icon );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this gateway is available in the user's country based on currency.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_valid_for_use() {
|
||||
return 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', 'INR' )
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Panel Options.
|
||||
* - Options for bits like 'title' and availability on a country-by-country basis.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function admin_options() {
|
||||
if ( $this->is_valid_for_use() ) {
|
||||
parent::admin_options();
|
||||
} else {
|
||||
?>
|
||||
<div class="inline error">
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'Gateway disabled', 'woocommerce' ); ?></strong>: <?php esc_html_e( 'PayPal Standard does not support your store currency.', 'woocommerce' ); ?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise Gateway Settings Form Fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = include __DIR__ . '/includes/settings-paypal.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the transaction URL.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ) {
|
||||
if ( $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';
|
||||
}
|
||||
return parent::get_transaction_url( $order );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the payment and return the result.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
include_once dirname( __FILE__ ) . '/includes/class-wc-gateway-paypal-request.php';
|
||||
|
||||
$order = wc_get_order( $order_id );
|
||||
$paypal_request = new WC_Gateway_Paypal_Request( $this );
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $paypal_request->get_request_url( $order, $this->testmode ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the order be refunded via PayPal?
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @return bool
|
||||
*/
|
||||
public function can_refund_order( $order ) {
|
||||
$has_api_creds = false;
|
||||
|
||||
if ( $this->testmode ) {
|
||||
$has_api_creds = $this->get_option( 'sandbox_api_username' ) && $this->get_option( 'sandbox_api_password' ) && $this->get_option( 'sandbox_api_signature' );
|
||||
} else {
|
||||
$has_api_creds = $this->get_option( 'api_username' ) && $this->get_option( 'api_password' ) && $this->get_option( 'api_signature' );
|
||||
}
|
||||
|
||||
return $order && $order->get_transaction_id() && $has_api_creds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the API class and set the username/password etc.
|
||||
*/
|
||||
protected function init_api() {
|
||||
include_once dirname( __FILE__ ) . '/includes/class-wc-gateway-paypal-api-handler.php';
|
||||
|
||||
WC_Gateway_Paypal_API_Handler::$api_username = $this->testmode ? $this->get_option( 'sandbox_api_username' ) : $this->get_option( 'api_username' );
|
||||
WC_Gateway_Paypal_API_Handler::$api_password = $this->testmode ? $this->get_option( 'sandbox_api_password' ) : $this->get_option( 'api_password' );
|
||||
WC_Gateway_Paypal_API_Handler::$api_signature = $this->testmode ? $this->get_option( 'sandbox_api_signature' ) : $this->get_option( 'api_signature' );
|
||||
WC_Gateway_Paypal_API_Handler::$sandbox = $this->testmode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a refund if supported.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( ! $this->can_refund_order( $order ) ) {
|
||||
return new WP_Error( 'error', __( 'Refund failed.', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
$this->init_api();
|
||||
|
||||
$result = WC_Gateway_Paypal_API_Handler::refund_transaction( $order, $amount, $reason );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$this->log( 'Refund Failed: ' . $result->get_error_message(), 'error' );
|
||||
return new WP_Error( 'error', $result->get_error_message() );
|
||||
}
|
||||
|
||||
$this->log( 'Refund Result: ' . wc_print_r( $result, true ) );
|
||||
|
||||
switch ( strtolower( $result->ACK ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
case 'success':
|
||||
case 'successwithwarning':
|
||||
$order->add_order_note(
|
||||
/* translators: 1: Refund amount, 2: Refund ID */
|
||||
sprintf( __( 'Refunded %1$s - Refund ID: %2$s', 'woocommerce' ), $result->GROSSREFUNDAMT, $result->REFUNDTRANSACTIONID ) // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
return isset( $result->L_LONGMESSAGE0 ) ? new WP_Error( 'error', $result->L_LONGMESSAGE0 ) : false; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture payment when the order is changed from on-hold to complete or processing
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
*/
|
||||
public function capture_payment( $order_id ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( 'paypal' === $order->get_payment_method() && 'pending' === $order->get_meta( '_paypal_status', true ) && $order->get_transaction_id() ) {
|
||||
$this->init_api();
|
||||
$result = WC_Gateway_Paypal_API_Handler::do_capture( $order );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$this->log( 'Capture Failed: ' . $result->get_error_message(), 'error' );
|
||||
/* translators: %s: Paypal gateway error message */
|
||||
$order->add_order_note( sprintf( __( 'Payment could not be captured: %s', 'woocommerce' ), $result->get_error_message() ) );
|
||||
return;
|
||||
}
|
||||
|
||||
$this->log( 'Capture Result: ' . wc_print_r( $result, true ) );
|
||||
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
if ( ! empty( $result->PAYMENTSTATUS ) ) {
|
||||
switch ( $result->PAYMENTSTATUS ) {
|
||||
case 'Completed':
|
||||
/* translators: 1: Amount, 2: Authorization ID, 3: Transaction ID */
|
||||
$order->add_order_note( sprintf( __( 'Payment of %1$s was captured - Auth ID: %2$s, Transaction ID: %3$s', 'woocommerce' ), $result->AMT, $result->AUTHORIZATIONID, $result->TRANSACTIONID ) );
|
||||
update_post_meta( $order->get_id(), '_paypal_status', $result->PAYMENTSTATUS );
|
||||
update_post_meta( $order->get_id(), '_transaction_id', $result->TRANSACTIONID );
|
||||
break;
|
||||
default:
|
||||
/* translators: 1: Authorization ID, 2: Payment status */
|
||||
$order->add_order_note( sprintf( __( 'Payment could not be captured - Auth ID: %1$s, Status: %2$s', 'woocommerce' ), $result->AUTHORIZATIONID, $result->PAYMENTSTATUS ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
// phpcs:enable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load admin scripts.
|
||||
*
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public function admin_scripts() {
|
||||
$screen = get_current_screen();
|
||||
$screen_id = $screen ? $screen->id : '';
|
||||
|
||||
if ( 'woocommerce_page_wc-settings' !== $screen_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$suffix = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
|
||||
$version = Constants::get_constant( 'WC_VERSION' );
|
||||
|
||||
wp_enqueue_script( 'woocommerce_paypal_admin', WC()->plugin_url() . '/includes/gateways/paypal/assets/js/paypal-admin' . $suffix . '.js', array(), $version, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom PayPal order received text.
|
||||
*
|
||||
* @since 3.9.0
|
||||
* @param string $text Default text.
|
||||
* @param WC_Order $order Order data.
|
||||
* @return string
|
||||
*/
|
||||
public function order_received_text( $text, $order ) {
|
||||
if ( $order && $this->id === $order->get_payment_method() ) {
|
||||
return esc_html__( 'Thank you for your payment. Your transaction has been completed, and a receipt for your purchase has been emailed to you. Log into your PayPal account to view transaction details.', 'woocommerce' );
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether PayPal Standard should be loaded or not.
|
||||
*
|
||||
* By default PayPal Standard isn't loaded on new installs or on existing sites which haven't set up the gateway.
|
||||
*
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @return bool Whether PayPal Standard should be loaded.
|
||||
*/
|
||||
public function should_load() {
|
||||
$option_key = '_should_load';
|
||||
$should_load = $this->get_option( $option_key );
|
||||
|
||||
if ( '' === $should_load ) {
|
||||
|
||||
// New installs without PayPal Standard enabled don't load it.
|
||||
if ( 'no' === $this->enabled && WC_Install::is_new_install() ) {
|
||||
$should_load = false;
|
||||
} else {
|
||||
$should_load = true;
|
||||
}
|
||||
|
||||
$this->update_option( $option_key, wc_bool_to_string( $should_load ) );
|
||||
} else {
|
||||
$should_load = wc_string_to_bool( $should_load );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow third-parties to filter whether PayPal Standard should be loaded or not.
|
||||
*
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @param bool $should_load Whether PayPal Standard should be loaded.
|
||||
* @param WC_Gateway_Paypal $this The WC_Gateway_Paypal instance.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_should_load_paypal_standard', $should_load, $this );
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,202 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WC_Gateway_Paypal_API_Handler file.
|
||||
*
|
||||
* @package WooCommerce\Gateways
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Refunds and other API requests such as capture.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class WC_Gateway_Paypal_API_Handler {
|
||||
|
||||
/**
|
||||
* API Username
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $api_username;
|
||||
|
||||
/**
|
||||
* API Password
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $api_password;
|
||||
|
||||
/**
|
||||
* API Signature
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $api_signature;
|
||||
|
||||
/**
|
||||
* Sandbox
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $sandbox = false;
|
||||
|
||||
/**
|
||||
* Get capture request args.
|
||||
* See https://developer.paypal.com/docs/classic/api/merchant/DoCapture_API_Operation_NVP/.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param float $amount Amount.
|
||||
* @return array
|
||||
*/
|
||||
public static function get_capture_request( $order, $amount = null ) {
|
||||
$request = array(
|
||||
'VERSION' => '84.0',
|
||||
'SIGNATURE' => self::$api_signature,
|
||||
'USER' => self::$api_username,
|
||||
'PWD' => self::$api_password,
|
||||
'METHOD' => 'DoCapture',
|
||||
'AUTHORIZATIONID' => $order->get_transaction_id(),
|
||||
'AMT' => number_format( is_null( $amount ) ? $order->get_total() : $amount, 2, '.', '' ),
|
||||
'CURRENCYCODE' => $order->get_currency(),
|
||||
'COMPLETETYPE' => 'Complete',
|
||||
);
|
||||
return apply_filters( 'woocommerce_paypal_capture_request', $request, $order, $amount );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get refund request args.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return array
|
||||
*/
|
||||
public static function get_refund_request( $order, $amount = null, $reason = '' ) {
|
||||
$request = array(
|
||||
'VERSION' => '84.0',
|
||||
'SIGNATURE' => self::$api_signature,
|
||||
'USER' => self::$api_username,
|
||||
'PWD' => self::$api_password,
|
||||
'METHOD' => 'RefundTransaction',
|
||||
'TRANSACTIONID' => $order->get_transaction_id(),
|
||||
'NOTE' => html_entity_decode( wc_trim_string( $reason, 255 ), ENT_NOQUOTES, 'UTF-8' ),
|
||||
'REFUNDTYPE' => 'Full',
|
||||
);
|
||||
if ( ! is_null( $amount ) ) {
|
||||
$request['AMT'] = number_format( $amount, 2, '.', '' );
|
||||
$request['CURRENCYCODE'] = $order->get_currency();
|
||||
$request['REFUNDTYPE'] = 'Partial';
|
||||
}
|
||||
return apply_filters( 'woocommerce_paypal_refund_request', $request, $order, $amount, $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture an authorization.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param float $amount Amount.
|
||||
* @return object Either an object of name value pairs for a success, or a WP_ERROR object.
|
||||
*/
|
||||
public static function do_capture( $order, $amount = null ) {
|
||||
$raw_response = wp_safe_remote_post(
|
||||
self::$sandbox ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp',
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'body' => self::get_capture_request( $order, $amount ),
|
||||
'timeout' => 70,
|
||||
'user-agent' => 'WooCommerce/' . WC()->version,
|
||||
'httpversion' => '1.1',
|
||||
)
|
||||
);
|
||||
|
||||
WC_Gateway_Paypal::log( 'DoCapture Response: ' . wc_print_r( $raw_response, true ) );
|
||||
|
||||
if ( is_wp_error( $raw_response ) ) {
|
||||
return $raw_response;
|
||||
} elseif ( empty( $raw_response['body'] ) ) {
|
||||
return new WP_Error( 'paypal-api', 'Empty Response' );
|
||||
}
|
||||
|
||||
parse_str( $raw_response['body'], $response );
|
||||
|
||||
return (object) $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refund an order via PayPal.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return object Either an object of name value pairs for a success, or a WP_ERROR object.
|
||||
*/
|
||||
public static function refund_transaction( $order, $amount = null, $reason = '' ) {
|
||||
$raw_response = wp_safe_remote_post(
|
||||
self::$sandbox ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp',
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'body' => self::get_refund_request( $order, $amount, $reason ),
|
||||
'timeout' => 70,
|
||||
'user-agent' => 'WooCommerce/' . WC()->version,
|
||||
'httpversion' => '1.1',
|
||||
)
|
||||
);
|
||||
|
||||
WC_Gateway_Paypal::log( 'Refund Response: ' . wc_print_r( $raw_response, true ) );
|
||||
|
||||
if ( is_wp_error( $raw_response ) ) {
|
||||
return $raw_response;
|
||||
} elseif ( empty( $raw_response['body'] ) ) {
|
||||
return new WP_Error( 'paypal-api', 'Empty Response' );
|
||||
}
|
||||
|
||||
parse_str( $raw_response['body'], $response );
|
||||
|
||||
return (object) $response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Here for backwards compatibility.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class WC_Gateway_Paypal_Refund extends WC_Gateway_Paypal_API_Handler {
|
||||
/**
|
||||
* Get refund request args. Proxy to WC_Gateway_Paypal_API_Handler::get_refund_request().
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_request( $order, $amount = null, $reason = '' ) {
|
||||
return self::get_refund_request( $order, $amount, $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an order refund.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @param bool $sandbox Whether to use sandbox mode or not.
|
||||
* @return object Either an object of name value pairs for a success, or a WP_ERROR object.
|
||||
*/
|
||||
public static function refund_order( $order, $amount = null, $reason = '', $sandbox = false ) {
|
||||
if ( $sandbox ) {
|
||||
self::$sandbox = $sandbox;
|
||||
}
|
||||
$result = self::refund_transaction( $order, $amount, $reason );
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
} else {
|
||||
return (array) $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,376 @@
|
||||
<?php
|
||||
/**
|
||||
* Handles responses from PayPal IPN.
|
||||
*
|
||||
* @package WooCommerce\PayPal
|
||||
* @version 3.3.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once dirname( __FILE__ ) . '/class-wc-gateway-paypal-response.php';
|
||||
|
||||
/**
|
||||
* WC_Gateway_Paypal_IPN_Handler class.
|
||||
*/
|
||||
class WC_Gateway_Paypal_IPN_Handler extends WC_Gateway_Paypal_Response {
|
||||
|
||||
/**
|
||||
* Receiver email address to validate.
|
||||
*
|
||||
* @var string Receiver email address.
|
||||
*/
|
||||
protected $receiver_email;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param bool $sandbox Use sandbox or not.
|
||||
* @param string $receiver_email Email to receive IPN from.
|
||||
*/
|
||||
public function __construct( $sandbox = false, $receiver_email = '' ) {
|
||||
add_action( 'woocommerce_api_wc_gateway_paypal', array( $this, 'check_response' ) );
|
||||
add_action( 'valid-paypal-standard-ipn-request', array( $this, 'valid_response' ) );
|
||||
|
||||
$this->receiver_email = $receiver_email;
|
||||
$this->sandbox = $sandbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for PayPal IPN Response.
|
||||
*/
|
||||
public function check_response() {
|
||||
if ( ! empty( $_POST ) && $this->validate_ipn() ) { // WPCS: CSRF ok.
|
||||
$posted = wp_unslash( $_POST ); // WPCS: CSRF ok, input var ok.
|
||||
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
|
||||
do_action( 'valid-paypal-standard-ipn-request', $posted );
|
||||
exit;
|
||||
}
|
||||
|
||||
wp_die( 'PayPal IPN Request Failure', 'PayPal IPN', array( 'response' => 500 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* There was a valid response.
|
||||
*
|
||||
* @param array $posted Post data after wp_unslash.
|
||||
*/
|
||||
public function valid_response( $posted ) {
|
||||
$order = ! empty( $posted['custom'] ) ? $this->get_paypal_order( $posted['custom'] ) : false;
|
||||
|
||||
if ( $order ) {
|
||||
|
||||
// Lowercase returned variables.
|
||||
$posted['payment_status'] = strtolower( $posted['payment_status'] );
|
||||
|
||||
WC_Gateway_Paypal::log( 'Found order #' . $order->get_id() );
|
||||
WC_Gateway_Paypal::log( 'Payment status: ' . $posted['payment_status'] );
|
||||
|
||||
if ( method_exists( $this, 'payment_status_' . $posted['payment_status'] ) ) {
|
||||
call_user_func( array( $this, 'payment_status_' . $posted['payment_status'] ), $order, $posted );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check PayPal IPN validity.
|
||||
*/
|
||||
public function validate_ipn() {
|
||||
WC_Gateway_Paypal::log( 'Checking IPN response is valid' );
|
||||
|
||||
// Get received values from post data.
|
||||
$validate_ipn = wp_unslash( $_POST ); // WPCS: CSRF ok, input var ok.
|
||||
$validate_ipn['cmd'] = '_notify-validate';
|
||||
|
||||
// Send back post vars to paypal.
|
||||
$params = array(
|
||||
'body' => $validate_ipn,
|
||||
'timeout' => 60,
|
||||
'httpversion' => '1.1',
|
||||
'compress' => false,
|
||||
'decompress' => false,
|
||||
'user-agent' => 'WooCommerce/' . WC()->version,
|
||||
);
|
||||
|
||||
// Post back to get a response.
|
||||
$response = wp_safe_remote_post( $this->sandbox ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr', $params );
|
||||
|
||||
WC_Gateway_Paypal::log( 'IPN Response: ' . wc_print_r( $response, true ) );
|
||||
|
||||
// Check to see if the request was valid.
|
||||
if ( ! is_wp_error( $response ) && $response['response']['code'] >= 200 && $response['response']['code'] < 300 && strstr( $response['body'], 'VERIFIED' ) ) {
|
||||
WC_Gateway_Paypal::log( 'Received valid response from PayPal IPN' );
|
||||
return true;
|
||||
}
|
||||
|
||||
WC_Gateway_Paypal::log( 'Received invalid response from PayPal IPN' );
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
WC_Gateway_Paypal::log( 'Error response: ' . $response->get_error_message() );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for a valid transaction type.
|
||||
*
|
||||
* @param string $txn_type Transaction type.
|
||||
*/
|
||||
protected function validate_transaction_type( $txn_type ) {
|
||||
$accepted_types = array( 'cart', 'instant', 'express_checkout', 'web_accept', 'masspay', 'send_money', 'paypal_here' );
|
||||
|
||||
if ( ! in_array( strtolower( $txn_type ), $accepted_types, true ) ) {
|
||||
WC_Gateway_Paypal::log( 'Aborting, Invalid type:' . $txn_type );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check currency from IPN matches the order.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param string $currency Currency code.
|
||||
*/
|
||||
protected function validate_currency( $order, $currency ) {
|
||||
if ( $order->get_currency() !== $currency ) {
|
||||
WC_Gateway_Paypal::log( 'Payment error: Currencies do not match (sent "' . $order->get_currency() . '" | returned "' . $currency . '")' );
|
||||
|
||||
/* translators: %s: currency code. */
|
||||
$order->update_status( 'on-hold', sprintf( __( 'Validation error: PayPal currencies do not match (code %s).', 'woocommerce' ), $currency ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check payment amount from IPN matches the order.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param int $amount Amount to validate.
|
||||
*/
|
||||
protected function validate_amount( $order, $amount ) {
|
||||
if ( number_format( $order->get_total(), 2, '.', '' ) !== number_format( $amount, 2, '.', '' ) ) {
|
||||
WC_Gateway_Paypal::log( 'Payment error: Amounts do not match (gross ' . $amount . ')' );
|
||||
|
||||
/* translators: %s: Amount. */
|
||||
$order->update_status( 'on-hold', sprintf( __( 'Validation error: PayPal amounts do not match (gross %s).', 'woocommerce' ), $amount ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check receiver email from PayPal. If the receiver email in the IPN is different than what is stored in.
|
||||
* WooCommerce -> Settings -> Checkout -> PayPal, it will log an error about it.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param string $receiver_email Email to validate.
|
||||
*/
|
||||
protected function validate_receiver_email( $order, $receiver_email ) {
|
||||
if ( strcasecmp( trim( $receiver_email ), trim( $this->receiver_email ) ) !== 0 ) {
|
||||
WC_Gateway_Paypal::log( "IPN Response is for another account: {$receiver_email}. Your email is {$this->receiver_email}" );
|
||||
|
||||
/* translators: %s: email address . */
|
||||
$order->update_status( 'on-hold', sprintf( __( 'Validation error: PayPal IPN response from a different email address (%s).', 'woocommerce' ), $receiver_email ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a completed payment.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function payment_status_completed( $order, $posted ) {
|
||||
if ( $order->has_status( wc_get_is_paid_statuses() ) ) {
|
||||
WC_Gateway_Paypal::log( 'Aborting, Order #' . $order->get_id() . ' is already complete.' );
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->validate_transaction_type( $posted['txn_type'] );
|
||||
$this->validate_currency( $order, $posted['mc_currency'] );
|
||||
$this->validate_amount( $order, $posted['mc_gross'] );
|
||||
$this->validate_receiver_email( $order, $posted['receiver_email'] );
|
||||
$this->save_paypal_meta_data( $order, $posted );
|
||||
|
||||
if ( 'completed' === $posted['payment_status'] ) {
|
||||
if ( $order->has_status( 'cancelled' ) ) {
|
||||
$this->payment_status_paid_cancelled_order( $order, $posted );
|
||||
}
|
||||
|
||||
if ( ! empty( $posted['mc_fee'] ) ) {
|
||||
$order->add_meta_data( 'PayPal Transaction Fee', wc_clean( $posted['mc_fee'] ) );
|
||||
}
|
||||
|
||||
$this->payment_complete( $order, ( ! empty( $posted['txn_id'] ) ? wc_clean( $posted['txn_id'] ) : '' ), __( 'IPN payment completed', 'woocommerce' ) );
|
||||
} else {
|
||||
if ( 'authorization' === $posted['pending_reason'] ) {
|
||||
$this->payment_on_hold( $order, __( 'Payment authorized. Change payment status to processing or complete to capture funds.', 'woocommerce' ) );
|
||||
} else {
|
||||
/* translators: %s: pending reason. */
|
||||
$this->payment_on_hold( $order, sprintf( __( 'Payment pending (%s).', 'woocommerce' ), $posted['pending_reason'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a pending payment.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function payment_status_pending( $order, $posted ) {
|
||||
$this->payment_status_completed( $order, $posted );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a failed payment.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function payment_status_failed( $order, $posted ) {
|
||||
/* translators: %s: payment status. */
|
||||
$order->update_status( 'failed', sprintf( __( 'Payment %s via IPN.', 'woocommerce' ), wc_clean( $posted['payment_status'] ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a denied payment.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function payment_status_denied( $order, $posted ) {
|
||||
$this->payment_status_failed( $order, $posted );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an expired payment.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function payment_status_expired( $order, $posted ) {
|
||||
$this->payment_status_failed( $order, $posted );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a voided payment.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function payment_status_voided( $order, $posted ) {
|
||||
$this->payment_status_failed( $order, $posted );
|
||||
}
|
||||
|
||||
/**
|
||||
* When a user cancelled order is marked paid.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function payment_status_paid_cancelled_order( $order, $posted ) {
|
||||
$this->send_ipn_email_notification(
|
||||
/* translators: %s: order link. */
|
||||
sprintf( __( 'Payment for cancelled order %s received', 'woocommerce' ), '<a class="link" href="' . esc_url( $order->get_edit_order_url() ) . '">' . $order->get_order_number() . '</a>' ),
|
||||
/* translators: %s: order ID. */
|
||||
sprintf( __( 'Order #%s has been marked paid by PayPal IPN, but was previously cancelled. Admin handling required.', 'woocommerce' ), $order->get_order_number() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a refunded order.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function payment_status_refunded( $order, $posted ) {
|
||||
// Only handle full refunds, not partial.
|
||||
if ( $order->get_total() === wc_format_decimal( $posted['mc_gross'] * -1, wc_get_price_decimals() ) ) {
|
||||
|
||||
/* translators: %s: payment status. */
|
||||
$order->update_status( 'refunded', sprintf( __( 'Payment %s via IPN.', 'woocommerce' ), strtolower( $posted['payment_status'] ) ) );
|
||||
|
||||
$this->send_ipn_email_notification(
|
||||
/* translators: %s: order link. */
|
||||
sprintf( __( 'Payment for order %s refunded', 'woocommerce' ), '<a class="link" href="' . esc_url( $order->get_edit_order_url() ) . '">' . $order->get_order_number() . '</a>' ),
|
||||
/* translators: %1$s: order ID, %2$s: reason code. */
|
||||
sprintf( __( 'Order #%1$s has been marked as refunded - PayPal reason code: %2$s', 'woocommerce' ), $order->get_order_number(), $posted['reason_code'] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a reversal.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function payment_status_reversed( $order, $posted ) {
|
||||
/* translators: %s: payment status. */
|
||||
$order->update_status( 'on-hold', sprintf( __( 'Payment %s via IPN.', 'woocommerce' ), wc_clean( $posted['payment_status'] ) ) );
|
||||
|
||||
$this->send_ipn_email_notification(
|
||||
/* translators: %s: order link. */
|
||||
sprintf( __( 'Payment for order %s reversed', 'woocommerce' ), '<a class="link" href="' . esc_url( $order->get_edit_order_url() ) . '">' . $order->get_order_number() . '</a>' ),
|
||||
/* translators: %1$s: order ID, %2$s: reason code. */
|
||||
sprintf( __( 'Order #%1$s has been marked on-hold due to a reversal - PayPal reason code: %2$s', 'woocommerce' ), $order->get_order_number(), wc_clean( $posted['reason_code'] ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a cancelled reversal.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function payment_status_canceled_reversal( $order, $posted ) {
|
||||
$this->send_ipn_email_notification(
|
||||
/* translators: %s: order link. */
|
||||
sprintf( __( 'Reversal cancelled for order #%s', 'woocommerce' ), $order->get_order_number() ),
|
||||
/* translators: %1$s: order ID, %2$s: order link. */
|
||||
sprintf( __( 'Order #%1$s has had a reversal cancelled. Please check the status of payment and update the order status accordingly here: %2$s', 'woocommerce' ), $order->get_order_number(), esc_url( $order->get_edit_order_url() ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save important data from the IPN to the order.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Posted data.
|
||||
*/
|
||||
protected function save_paypal_meta_data( $order, $posted ) {
|
||||
if ( ! empty( $posted['payment_type'] ) ) {
|
||||
update_post_meta( $order->get_id(), 'Payment type', wc_clean( $posted['payment_type'] ) );
|
||||
}
|
||||
if ( ! empty( $posted['txn_id'] ) ) {
|
||||
update_post_meta( $order->get_id(), '_transaction_id', wc_clean( $posted['txn_id'] ) );
|
||||
}
|
||||
if ( ! empty( $posted['payment_status'] ) ) {
|
||||
update_post_meta( $order->get_id(), '_paypal_status', wc_clean( $posted['payment_status'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a notification to the user handling orders.
|
||||
*
|
||||
* @param string $subject Email subject.
|
||||
* @param string $message Email message.
|
||||
*/
|
||||
protected 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 );
|
||||
|
||||
$woocommerce_paypal_settings = get_option( 'woocommerce_paypal_settings' );
|
||||
if ( ! empty( $woocommerce_paypal_settings['ipn_notification'] ) && 'no' === $woocommerce_paypal_settings['ipn_notification'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$mailer->send( ! empty( $new_order_settings['recipient'] ) ? $new_order_settings['recipient'] : get_option( 'admin_email' ), strip_tags( $subject ), $message );
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WC_Gateway_Paypal_PDT_Handler file.
|
||||
*
|
||||
* @package WooCommerce\Gateways
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once dirname( __FILE__ ) . '/class-wc-gateway-paypal-response.php';
|
||||
|
||||
/**
|
||||
* Handle PDT Responses from PayPal.
|
||||
*/
|
||||
class WC_Gateway_Paypal_PDT_Handler extends WC_Gateway_Paypal_Response {
|
||||
|
||||
/**
|
||||
* Identity token for PDT support
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $identity_token;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param bool $sandbox Whether to use sandbox mode or not.
|
||||
* @param string $identity_token Identity token for PDT support.
|
||||
*/
|
||||
public function __construct( $sandbox = false, $identity_token = '' ) {
|
||||
add_action( 'woocommerce_thankyou_paypal', array( $this, 'check_response' ) );
|
||||
|
||||
$this->identity_token = $identity_token;
|
||||
$this->sandbox = $sandbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a PDT transaction to ensure its authentic.
|
||||
*
|
||||
* @param string $transaction TX ID.
|
||||
* @return bool|array False or result array if successful and valid.
|
||||
*/
|
||||
protected function validate_transaction( $transaction ) {
|
||||
$pdt = array(
|
||||
'body' => array(
|
||||
'cmd' => '_notify-synch',
|
||||
'tx' => $transaction,
|
||||
'at' => $this->identity_token,
|
||||
),
|
||||
'timeout' => 60,
|
||||
'httpversion' => '1.1',
|
||||
'user-agent' => 'WooCommerce/' . Constants::get_constant( 'WC_VERSION' ),
|
||||
);
|
||||
|
||||
// Post back to get a response.
|
||||
$response = wp_safe_remote_post( $this->sandbox ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr', $pdt );
|
||||
|
||||
if ( is_wp_error( $response ) || strpos( $response['body'], 'SUCCESS' ) !== 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse transaction result data.
|
||||
$transaction_result = array_map( 'wc_clean', array_map( 'urldecode', explode( "\n", $response['body'] ) ) );
|
||||
$transaction_results = array();
|
||||
|
||||
foreach ( $transaction_result as $line ) {
|
||||
$line = explode( '=', $line );
|
||||
$transaction_results[ $line[0] ] = isset( $line[1] ) ? $line[1] : '';
|
||||
}
|
||||
|
||||
if ( ! empty( $transaction_results['charset'] ) && function_exists( 'iconv' ) ) {
|
||||
foreach ( $transaction_results as $key => $value ) {
|
||||
$transaction_results[ $key ] = iconv( $transaction_results['charset'], 'utf-8', $value );
|
||||
}
|
||||
}
|
||||
|
||||
return $transaction_results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Response for PDT.
|
||||
*/
|
||||
public function check_response() {
|
||||
if ( empty( $_REQUEST['cm'] ) || empty( $_REQUEST['tx'] ) || empty( $_REQUEST['st'] ) ) { // WPCS: Input var ok, CSRF ok, sanitization ok.
|
||||
return;
|
||||
}
|
||||
|
||||
$order_id = wc_clean( wp_unslash( $_REQUEST['cm'] ) ); // WPCS: input var ok, CSRF ok, sanitization ok.
|
||||
$status = wc_clean( strtolower( wp_unslash( $_REQUEST['st'] ) ) ); // WPCS: input var ok, CSRF ok, sanitization ok.
|
||||
$amount = isset( $_REQUEST['amt'] ) ? wc_clean( wp_unslash( $_REQUEST['amt'] ) ) : 0; // WPCS: input var ok, CSRF ok, sanitization ok.
|
||||
$transaction = wc_clean( wp_unslash( $_REQUEST['tx'] ) ); // WPCS: input var ok, CSRF ok, sanitization ok.
|
||||
$order = $this->get_paypal_order( $order_id );
|
||||
|
||||
if ( ! $order || ! $order->needs_payment() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$transaction_result = $this->validate_transaction( $transaction );
|
||||
|
||||
if ( $transaction_result ) {
|
||||
WC_Gateway_Paypal::log( 'PDT Transaction Status: ' . wc_print_r( $status, true ) );
|
||||
|
||||
$order->add_meta_data( '_paypal_status', $status );
|
||||
$order->set_transaction_id( $transaction );
|
||||
|
||||
if ( 'completed' === $status ) {
|
||||
if ( number_format( $order->get_total(), 2, '.', '' ) !== number_format( $amount, 2, '.', '' ) ) {
|
||||
WC_Gateway_Paypal::log( 'Payment error: Amounts do not match (amt ' . $amount . ')', 'error' );
|
||||
/* translators: 1: Payment amount */
|
||||
$this->payment_on_hold( $order, sprintf( __( 'Validation error: PayPal amounts do not match (amt %s).', 'woocommerce' ), $amount ) );
|
||||
} else {
|
||||
// Log paypal transaction fee and payment type.
|
||||
if ( ! empty( $transaction_result['mc_fee'] ) ) {
|
||||
$order->add_meta_data( 'PayPal Transaction Fee', wc_clean( $transaction_result['mc_fee'] ) );
|
||||
}
|
||||
if ( ! empty( $transaction_result['payment_type'] ) ) {
|
||||
$order->add_meta_data( 'Payment type', wc_clean( $transaction_result['payment_type'] ) );
|
||||
}
|
||||
|
||||
$this->payment_complete( $order, $transaction, __( 'PDT payment completed', 'woocommerce' ) );
|
||||
}
|
||||
} else {
|
||||
if ( 'authorization' === $transaction_result['pending_reason'] ) {
|
||||
$this->payment_on_hold( $order, __( 'Payment authorized. Change payment status to processing or complete to capture funds.', 'woocommerce' ) );
|
||||
} else {
|
||||
/* translators: 1: Pending reason */
|
||||
$this->payment_on_hold( $order, sprintf( __( 'Payment pending (%s).', 'woocommerce' ), $transaction_result['pending_reason'] ) );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WC_Gateway_Paypal::log( 'Received invalid response from PayPal PDT' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,580 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WC_Gateway_Paypal_Request file.
|
||||
*
|
||||
* @package WooCommerce\Gateways
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates requests to send to PayPal.
|
||||
*/
|
||||
class WC_Gateway_Paypal_Request {
|
||||
|
||||
/**
|
||||
* Stores line items to send to PayPal.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $line_items = array();
|
||||
|
||||
/**
|
||||
* Pointer to gateway making the request.
|
||||
*
|
||||
* @var WC_Gateway_Paypal
|
||||
*/
|
||||
protected $gateway;
|
||||
|
||||
/**
|
||||
* Endpoint for requests from PayPal.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $notify_url;
|
||||
|
||||
/**
|
||||
* Endpoint for requests to PayPal.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $endpoint;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param WC_Gateway_Paypal $gateway Paypal gateway object.
|
||||
*/
|
||||
public function __construct( $gateway ) {
|
||||
$this->gateway = $gateway;
|
||||
$this->notify_url = WC()->api_request_url( 'WC_Gateway_Paypal' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PayPal request URL for an order.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param bool $sandbox Whether to use sandbox mode or not.
|
||||
* @return string
|
||||
*/
|
||||
public function get_request_url( $order, $sandbox = false ) {
|
||||
$this->endpoint = $sandbox ? 'https://www.sandbox.paypal.com/cgi-bin/webscr?test_ipn=1&' : 'https://www.paypal.com/cgi-bin/webscr?';
|
||||
$paypal_args = $this->get_paypal_args( $order );
|
||||
$paypal_args['bn'] = 'WooThemes_Cart'; // Append WooCommerce PayPal Partner Attribution ID. This should not be overridden for this gateway.
|
||||
|
||||
// Mask (remove) PII from the logs.
|
||||
$mask = array(
|
||||
'first_name' => '***',
|
||||
'last_name' => '***',
|
||||
'address1' => '***',
|
||||
'address2' => '***',
|
||||
'city' => '***',
|
||||
'state' => '***',
|
||||
'zip' => '***',
|
||||
'country' => '***',
|
||||
'email' => '***@***',
|
||||
'night_phone_a' => '***',
|
||||
'night_phone_b' => '***',
|
||||
'night_phone_c' => '***',
|
||||
);
|
||||
|
||||
WC_Gateway_Paypal::log( 'PayPal Request Args for order ' . $order->get_order_number() . ': ' . wc_print_r( array_merge( $paypal_args, array_intersect_key( $mask, $paypal_args ) ), true ) );
|
||||
|
||||
return $this->endpoint . http_build_query( $paypal_args, '', '&' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit length of an arg.
|
||||
*
|
||||
* @param string $string Argument to limit.
|
||||
* @param integer $limit Limit size in characters.
|
||||
* @return string
|
||||
*/
|
||||
protected function limit_length( $string, $limit = 127 ) {
|
||||
$str_limit = $limit - 3;
|
||||
if ( function_exists( 'mb_strimwidth' ) ) {
|
||||
if ( mb_strlen( $string ) > $limit ) {
|
||||
$string = mb_strimwidth( $string, 0, $str_limit ) . '...';
|
||||
}
|
||||
} else {
|
||||
if ( strlen( $string ) > $limit ) {
|
||||
$string = substr( $string, 0, $str_limit ) . '...';
|
||||
}
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transaction args for paypal request, except for line item args.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_transaction_args( $order ) {
|
||||
return array_merge(
|
||||
array(
|
||||
'cmd' => '_cart',
|
||||
'business' => $this->gateway->get_option( 'email' ),
|
||||
'no_note' => 1,
|
||||
'currency_code' => get_woocommerce_currency(),
|
||||
'charset' => 'utf-8',
|
||||
'rm' => is_ssl() ? 2 : 1,
|
||||
'upload' => 1,
|
||||
'return' => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->gateway->get_return_url( $order ) ) ),
|
||||
'cancel_return' => esc_url_raw( $order->get_cancel_order_url_raw() ),
|
||||
'image_url' => esc_url_raw( $this->gateway->get_option( 'image_url' ) ),
|
||||
'paymentaction' => $this->gateway->get_option( 'paymentaction' ),
|
||||
'invoice' => $this->limit_length( $this->gateway->get_option( 'invoice_prefix' ) . $order->get_order_number(), 127 ),
|
||||
'custom' => wp_json_encode(
|
||||
array(
|
||||
'order_id' => $order->get_id(),
|
||||
'order_key' => $order->get_order_key(),
|
||||
)
|
||||
),
|
||||
'notify_url' => $this->limit_length( $this->notify_url, 255 ),
|
||||
'first_name' => $this->limit_length( $order->get_billing_first_name(), 32 ),
|
||||
'last_name' => $this->limit_length( $order->get_billing_last_name(), 64 ),
|
||||
'address1' => $this->limit_length( $order->get_billing_address_1(), 100 ),
|
||||
'address2' => $this->limit_length( $order->get_billing_address_2(), 100 ),
|
||||
'city' => $this->limit_length( $order->get_billing_city(), 40 ),
|
||||
'state' => $this->get_paypal_state( $order->get_billing_country(), $order->get_billing_state() ),
|
||||
'zip' => $this->limit_length( wc_format_postcode( $order->get_billing_postcode(), $order->get_billing_country() ), 32 ),
|
||||
'country' => $this->limit_length( $order->get_billing_country(), 2 ),
|
||||
'email' => $this->limit_length( $order->get_billing_email() ),
|
||||
),
|
||||
$this->get_phone_number_args( $order ),
|
||||
$this->get_shipping_args( $order )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the default request with line items is too long, generate a new one with only one line item.
|
||||
*
|
||||
* If URL is longer than 2,083 chars, ignore line items and send cart to Paypal as a single item.
|
||||
* One item's name can only be 127 characters long, so the URL should not be longer than limit.
|
||||
* URL character limit via:
|
||||
* https://support.microsoft.com/en-us/help/208427/maximum-url-length-is-2-083-characters-in-internet-explorer.
|
||||
*
|
||||
* @param WC_Order $order Order to be sent to Paypal.
|
||||
* @param array $paypal_args Arguments sent to Paypal in the request.
|
||||
* @return array
|
||||
*/
|
||||
protected function fix_request_length( $order, $paypal_args ) {
|
||||
$max_paypal_length = 2083;
|
||||
$query_candidate = http_build_query( $paypal_args, '', '&' );
|
||||
|
||||
if ( strlen( $this->endpoint . $query_candidate ) <= $max_paypal_length ) {
|
||||
return $paypal_args;
|
||||
}
|
||||
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_args',
|
||||
array_merge(
|
||||
$this->get_transaction_args( $order ),
|
||||
$this->get_line_item_args( $order, true )
|
||||
),
|
||||
$order
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PayPal Args for passing to PP.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_paypal_args( $order ) {
|
||||
WC_Gateway_Paypal::log( 'Generating payment form for order ' . $order->get_order_number() . '. Notify URL: ' . $this->notify_url );
|
||||
|
||||
$force_one_line_item = apply_filters( 'woocommerce_paypal_force_one_line_item', false, $order );
|
||||
|
||||
if ( ( wc_tax_enabled() && wc_prices_include_tax() ) || ! $this->line_items_valid( $order ) ) {
|
||||
$force_one_line_item = true;
|
||||
}
|
||||
|
||||
$paypal_args = apply_filters(
|
||||
'woocommerce_paypal_args',
|
||||
array_merge(
|
||||
$this->get_transaction_args( $order ),
|
||||
$this->get_line_item_args( $order, $force_one_line_item )
|
||||
),
|
||||
$order
|
||||
);
|
||||
|
||||
return $this->fix_request_length( $order, $paypal_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get phone number args for paypal request.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_phone_number_args( $order ) {
|
||||
$phone_number = wc_sanitize_phone_number( $order->get_billing_phone() );
|
||||
|
||||
if ( in_array( $order->get_billing_country(), array( 'US', 'CA' ), true ) ) {
|
||||
$phone_number = ltrim( $phone_number, '+1' );
|
||||
$phone_args = array(
|
||||
'night_phone_a' => substr( $phone_number, 0, 3 ),
|
||||
'night_phone_b' => substr( $phone_number, 3, 3 ),
|
||||
'night_phone_c' => substr( $phone_number, 6, 4 ),
|
||||
);
|
||||
} else {
|
||||
$calling_code = WC()->countries->get_country_calling_code( $order->get_billing_country() );
|
||||
$calling_code = is_array( $calling_code ) ? $calling_code[0] : $calling_code;
|
||||
|
||||
if ( $calling_code ) {
|
||||
$phone_number = str_replace( $calling_code, '', preg_replace( '/^0/', '', $order->get_billing_phone() ) );
|
||||
}
|
||||
|
||||
$phone_args = array(
|
||||
'night_phone_a' => $calling_code,
|
||||
'night_phone_b' => $phone_number,
|
||||
);
|
||||
}
|
||||
return $phone_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping args for paypal request.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_shipping_args( $order ) {
|
||||
$shipping_args = array();
|
||||
if ( $order->needs_shipping_address() ) {
|
||||
$shipping_args['address_override'] = $this->gateway->get_option( 'address_override' ) === 'yes' ? 1 : 0;
|
||||
$shipping_args['no_shipping'] = 0;
|
||||
if ( 'yes' === $this->gateway->get_option( 'send_shipping' ) ) {
|
||||
// If we are sending shipping, send shipping address instead of billing.
|
||||
$shipping_args['first_name'] = $this->limit_length( $order->get_shipping_first_name(), 32 );
|
||||
$shipping_args['last_name'] = $this->limit_length( $order->get_shipping_last_name(), 64 );
|
||||
$shipping_args['address1'] = $this->limit_length( $order->get_shipping_address_1(), 100 );
|
||||
$shipping_args['address2'] = $this->limit_length( $order->get_shipping_address_2(), 100 );
|
||||
$shipping_args['city'] = $this->limit_length( $order->get_shipping_city(), 40 );
|
||||
$shipping_args['state'] = $this->get_paypal_state( $order->get_shipping_country(), $order->get_shipping_state() );
|
||||
$shipping_args['country'] = $this->limit_length( $order->get_shipping_country(), 2 );
|
||||
$shipping_args['zip'] = $this->limit_length( wc_format_postcode( $order->get_shipping_postcode(), $order->get_shipping_country() ), 32 );
|
||||
}
|
||||
} else {
|
||||
$shipping_args['no_shipping'] = 1;
|
||||
}
|
||||
return $shipping_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipping cost line item args for paypal request.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param bool $force_one_line_item Whether one line item was forced by validation or URL length.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_shipping_cost_line_item( $order, $force_one_line_item ) {
|
||||
$line_item_args = array();
|
||||
$shipping_total = $order->get_shipping_total();
|
||||
if ( $force_one_line_item ) {
|
||||
$shipping_total += $order->get_shipping_tax();
|
||||
}
|
||||
|
||||
// Add shipping costs. Paypal ignores anything over 5 digits (999.99 is the max).
|
||||
// We also check that shipping is not the **only** cost as PayPal won't allow payment
|
||||
// if the items have no cost.
|
||||
if ( $order->get_shipping_total() > 0 && $order->get_shipping_total() < 999.99 && $this->number_format( $order->get_shipping_total() + $order->get_shipping_tax(), $order ) !== $this->number_format( $order->get_total(), $order ) ) {
|
||||
$line_item_args['shipping_1'] = $this->number_format( $shipping_total, $order );
|
||||
} elseif ( $order->get_shipping_total() > 0 ) {
|
||||
/* translators: %s: Order shipping method */
|
||||
$this->add_line_item( sprintf( __( 'Shipping via %s', 'woocommerce' ), $order->get_shipping_method() ), 1, $this->number_format( $shipping_total, $order ) );
|
||||
}
|
||||
|
||||
return $line_item_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get line item args for paypal request as a single line item.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_line_item_args_single_item( $order ) {
|
||||
$this->delete_line_items();
|
||||
|
||||
$all_items_name = $this->get_order_item_names( $order );
|
||||
$this->add_line_item( $all_items_name ? $all_items_name : __( 'Order', 'woocommerce' ), 1, $this->number_format( $order->get_total() - $this->round( $order->get_shipping_total() + $order->get_shipping_tax(), $order ), $order ), $order->get_order_number() );
|
||||
$line_item_args = $this->get_shipping_cost_line_item( $order, true );
|
||||
|
||||
return array_merge( $line_item_args, $this->get_line_items() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get line item args for paypal request.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param bool $force_one_line_item Create only one item for this order.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_line_item_args( $order, $force_one_line_item = false ) {
|
||||
$line_item_args = array();
|
||||
|
||||
if ( $force_one_line_item ) {
|
||||
/**
|
||||
* Send order as a single item.
|
||||
*
|
||||
* For shipping, we longer use shipping_1 because paypal ignores it if *any* shipping rules are within paypal, and paypal ignores anything over 5 digits (999.99 is the max).
|
||||
*/
|
||||
$line_item_args = $this->get_line_item_args_single_item( $order );
|
||||
} else {
|
||||
/**
|
||||
* Passing a line item per product if supported.
|
||||
*/
|
||||
$this->prepare_line_items( $order );
|
||||
$line_item_args['tax_cart'] = $this->number_format( $order->get_total_tax(), $order );
|
||||
|
||||
if ( $order->get_total_discount() > 0 ) {
|
||||
$line_item_args['discount_amount_cart'] = $this->number_format( $this->round( $order->get_total_discount(), $order ), $order );
|
||||
}
|
||||
|
||||
$line_item_args = array_merge( $line_item_args, $this->get_shipping_cost_line_item( $order, false ) );
|
||||
$line_item_args = array_merge( $line_item_args, $this->get_line_items() );
|
||||
|
||||
}
|
||||
|
||||
return $line_item_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order item names as a string.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_order_item_names( $order ) {
|
||||
$item_names = array();
|
||||
|
||||
foreach ( $order->get_items() as $item ) {
|
||||
$item_name = $item->get_name();
|
||||
$item_meta = wp_strip_all_tags(
|
||||
wc_display_item_meta(
|
||||
$item,
|
||||
array(
|
||||
'before' => '',
|
||||
'separator' => ', ',
|
||||
'after' => '',
|
||||
'echo' => false,
|
||||
'autop' => false,
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ( $item_meta ) {
|
||||
$item_name .= ' (' . $item_meta . ')';
|
||||
}
|
||||
|
||||
$item_names[] = $item_name . ' x ' . $item->get_quantity();
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_paypal_get_order_item_names', implode( ', ', $item_names ), $order );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order item names as a string.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param WC_Order_Item $item Order item object.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_order_item_name( $order, $item ) {
|
||||
$item_name = $item->get_name();
|
||||
$item_meta = wp_strip_all_tags(
|
||||
wc_display_item_meta(
|
||||
$item,
|
||||
array(
|
||||
'before' => '',
|
||||
'separator' => ', ',
|
||||
'after' => '',
|
||||
'echo' => false,
|
||||
'autop' => false,
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ( $item_meta ) {
|
||||
$item_name .= ' (' . $item_meta . ')';
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_paypal_get_order_item_name', $item_name, $order, $item );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all line items.
|
||||
*/
|
||||
protected function get_line_items() {
|
||||
return $this->line_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all line items.
|
||||
*/
|
||||
protected function delete_line_items() {
|
||||
$this->line_items = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the order has valid line items to use for PayPal request.
|
||||
*
|
||||
* The line items are invalid in case of mismatch in totals or if any amount < 0.
|
||||
*
|
||||
* @param WC_Order $order Order to be examined.
|
||||
* @return bool
|
||||
*/
|
||||
protected function line_items_valid( $order ) {
|
||||
$negative_item_amount = false;
|
||||
$calculated_total = 0;
|
||||
|
||||
// Products.
|
||||
foreach ( $order->get_items( array( 'line_item', 'fee' ) ) as $item ) {
|
||||
if ( 'fee' === $item['type'] ) {
|
||||
$item_line_total = $this->number_format( $item['line_total'], $order );
|
||||
$calculated_total += $item_line_total;
|
||||
} else {
|
||||
$item_line_total = $this->number_format( $order->get_item_subtotal( $item, false ), $order );
|
||||
$calculated_total += $item_line_total * $item->get_quantity();
|
||||
}
|
||||
|
||||
if ( $item_line_total < 0 ) {
|
||||
$negative_item_amount = true;
|
||||
}
|
||||
}
|
||||
$mismatched_totals = $this->number_format( $calculated_total + $order->get_total_tax() + $this->round( $order->get_shipping_total(), $order ) - $this->round( $order->get_total_discount(), $order ), $order ) !== $this->number_format( $order->get_total(), $order );
|
||||
return ! $negative_item_amount && ! $mismatched_totals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get line items to send to paypal.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
*/
|
||||
protected function prepare_line_items( $order ) {
|
||||
$this->delete_line_items();
|
||||
|
||||
// Products.
|
||||
foreach ( $order->get_items( array( 'line_item', 'fee' ) ) as $item ) {
|
||||
if ( 'fee' === $item['type'] ) {
|
||||
$item_line_total = $this->number_format( $item['line_total'], $order );
|
||||
$this->add_line_item( $item->get_name(), 1, $item_line_total );
|
||||
} else {
|
||||
$product = $item->get_product();
|
||||
$sku = $product ? $product->get_sku() : '';
|
||||
$item_line_total = $this->number_format( $order->get_item_subtotal( $item, false ), $order );
|
||||
$this->add_line_item( $this->get_order_item_name( $order, $item ), $item->get_quantity(), $item_line_total, $sku );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add PayPal Line Item.
|
||||
*
|
||||
* @param string $item_name Item name.
|
||||
* @param int $quantity Item quantity.
|
||||
* @param float $amount Amount.
|
||||
* @param string $item_number Item number.
|
||||
*/
|
||||
protected function add_line_item( $item_name, $quantity = 1, $amount = 0.0, $item_number = '' ) {
|
||||
$index = ( count( $this->line_items ) / 4 ) + 1;
|
||||
|
||||
$item = apply_filters(
|
||||
'woocommerce_paypal_line_item',
|
||||
array(
|
||||
'item_name' => html_entity_decode( wc_trim_string( $item_name ? wp_strip_all_tags( $item_name ) : __( 'Item', 'woocommerce' ), 127 ), ENT_NOQUOTES, 'UTF-8' ),
|
||||
'quantity' => (int) $quantity,
|
||||
'amount' => wc_float_to_string( (float) $amount ),
|
||||
'item_number' => $item_number,
|
||||
),
|
||||
$item_name,
|
||||
$quantity,
|
||||
$amount,
|
||||
$item_number
|
||||
);
|
||||
|
||||
$this->line_items[ 'item_name_' . $index ] = $this->limit_length( $item['item_name'], 127 );
|
||||
$this->line_items[ 'quantity_' . $index ] = $item['quantity'];
|
||||
$this->line_items[ 'amount_' . $index ] = $item['amount'];
|
||||
$this->line_items[ 'item_number_' . $index ] = $this->limit_length( $item['item_number'], 127 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state to send to paypal.
|
||||
*
|
||||
* @param string $cc Country two letter code.
|
||||
* @param string $state State code.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_paypal_state( $cc, $state ) {
|
||||
if ( 'US' === $cc ) {
|
||||
return $state;
|
||||
}
|
||||
|
||||
$states = WC()->countries->get_states( $cc );
|
||||
|
||||
if ( isset( $states[ $state ] ) ) {
|
||||
return $states[ $state ];
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if currency has decimals.
|
||||
*
|
||||
* @param string $currency Currency to check.
|
||||
* @return bool
|
||||
*/
|
||||
protected function currency_has_decimals( $currency ) {
|
||||
if ( in_array( $currency, array( 'HUF', 'JPY', 'TWD' ), true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Round prices.
|
||||
*
|
||||
* @param double $price Price to round.
|
||||
* @param WC_Order $order Order object.
|
||||
* @return double
|
||||
*/
|
||||
protected function round( $price, $order ) {
|
||||
$precision = 2;
|
||||
|
||||
if ( ! $this->currency_has_decimals( $order->get_currency() ) ) {
|
||||
$precision = 0;
|
||||
}
|
||||
|
||||
return NumberUtil::round( $price, $precision );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format prices.
|
||||
*
|
||||
* @param float|int $price Price to format.
|
||||
* @param WC_Order $order Order object.
|
||||
* @return string
|
||||
*/
|
||||
protected function number_format( $price, $order ) {
|
||||
$decimals = 2;
|
||||
|
||||
if ( ! $this->currency_has_decimals( $order->get_currency() ) ) {
|
||||
$decimals = 0;
|
||||
}
|
||||
|
||||
return number_format( $price, $decimals, '.', '' );
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* Class WC_Gateway_Paypal_Response file.
|
||||
*
|
||||
* @package WooCommerce\Gateways
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Responses.
|
||||
*/
|
||||
abstract class WC_Gateway_Paypal_Response {
|
||||
|
||||
/**
|
||||
* Sandbox mode
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $sandbox = false;
|
||||
|
||||
/**
|
||||
* Get the order from the PayPal 'Custom' variable.
|
||||
*
|
||||
* @param string $raw_custom JSON Data passed back by PayPal.
|
||||
* @return bool|WC_Order object
|
||||
*/
|
||||
protected function get_paypal_order( $raw_custom ) {
|
||||
// We have the data in the correct format, so get the order.
|
||||
$custom = json_decode( $raw_custom );
|
||||
if ( $custom && is_object( $custom ) ) {
|
||||
$order_id = $custom->order_id;
|
||||
$order_key = $custom->order_key;
|
||||
} else {
|
||||
// Nothing was found.
|
||||
WC_Gateway_Paypal::log( 'Order ID and key were not found in "custom".', 'error' );
|
||||
return false;
|
||||
}
|
||||
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( ! $order ) {
|
||||
// We have an invalid $order_id, probably because invoice_prefix has changed.
|
||||
$order_id = wc_get_order_id_by_order_key( $order_key );
|
||||
$order = wc_get_order( $order_id );
|
||||
}
|
||||
|
||||
if ( ! $order || ! hash_equals( $order->get_order_key(), $order_key ) ) {
|
||||
WC_Gateway_Paypal::log( 'Order Keys do not match.', 'error' );
|
||||
return false;
|
||||
}
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete order, add transaction ID and note.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param string $txn_id Transaction ID.
|
||||
* @param string $note Payment note.
|
||||
*/
|
||||
protected function payment_complete( $order, $txn_id = '', $note = '' ) {
|
||||
if ( ! $order->has_status( array( 'processing', 'completed' ) ) ) {
|
||||
$order->add_order_note( $note );
|
||||
$order->payment_complete( $txn_id );
|
||||
|
||||
if ( isset( WC()->cart ) ) {
|
||||
WC()->cart->empty_cart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hold order and add note.
|
||||
*
|
||||
* @param WC_Order $order Order object.
|
||||
* @param string $reason Reason why the payment is on hold.
|
||||
*/
|
||||
protected function payment_on_hold( $order, $reason = '' ) {
|
||||
$order->update_status( 'on-hold', $reason );
|
||||
|
||||
if ( isset( WC()->cart ) ) {
|
||||
WC()->cart->empty_cart();
|
||||
}
|
||||
}
|
||||
}
|
||||
178
includes/gateways/paypal/includes/settings-paypal.php
Normal file
178
includes/gateways/paypal/includes/settings-paypal.php
Normal file
@ -0,0 +1,178 @@
|
||||
<?php
|
||||
/**
|
||||
* Settings for PayPal Standard Gateway.
|
||||
*
|
||||
* @package WooCommerce\Classes\Payment
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
return array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable PayPal Standard', 'woocommerce' ),
|
||||
'default' => 'no',
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce' ),
|
||||
'type' => 'text',
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
|
||||
'default' => __( 'PayPal', 'woocommerce' ),
|
||||
'desc_tip' => true,
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce' ),
|
||||
'default' => __( "Pay via PayPal; you can pay with your credit card if you don't have a PayPal account.", 'woocommerce' ),
|
||||
),
|
||||
'email' => array(
|
||||
'title' => __( 'PayPal email', 'woocommerce' ),
|
||||
'type' => 'email',
|
||||
'description' => __( 'Please enter your PayPal email address; this is needed in order to take payment.', 'woocommerce' ),
|
||||
'default' => get_option( 'admin_email' ),
|
||||
'desc_tip' => true,
|
||||
'placeholder' => 'you@youremail.com',
|
||||
),
|
||||
'advanced' => array(
|
||||
'title' => __( 'Advanced options', 'woocommerce' ),
|
||||
'type' => 'title',
|
||||
'description' => '',
|
||||
),
|
||||
'testmode' => array(
|
||||
'title' => __( 'PayPal sandbox', 'woocommerce' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable PayPal sandbox', 'woocommerce' ),
|
||||
'default' => 'no',
|
||||
/* translators: %s: URL */
|
||||
'description' => sprintf( __( 'PayPal sandbox can be used to test payments. Sign up for a <a href="%s">developer account</a>.', 'woocommerce' ), 'https://developer.paypal.com/' ),
|
||||
),
|
||||
'debug' => array(
|
||||
'title' => __( 'Debug log', 'woocommerce' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable logging', 'woocommerce' ),
|
||||
'default' => 'no',
|
||||
/* translators: %s: URL */
|
||||
'description' => sprintf( __( 'Log PayPal events, such as IPN requests, inside %s Note: this may log personal information. We recommend using this for debugging purposes only and deleting the logs when finished.', 'woocommerce' ), '<code>' . WC_Log_Handler_File::get_log_file_path( 'paypal' ) . '</code>' ),
|
||||
),
|
||||
'ipn_notification' => array(
|
||||
'title' => __( 'IPN email notifications', 'woocommerce' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable IPN email notifications', 'woocommerce' ),
|
||||
'default' => 'yes',
|
||||
'description' => __( 'Send notifications when an IPN is received from PayPal indicating refunds, chargebacks and cancellations.', 'woocommerce' ),
|
||||
),
|
||||
'receiver_email' => array(
|
||||
'title' => __( 'Receiver email', 'woocommerce' ),
|
||||
'type' => 'email',
|
||||
'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' ),
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'placeholder' => 'you@youremail.com',
|
||||
),
|
||||
'identity_token' => array(
|
||||
'title' => __( 'PayPal identity token', 'woocommerce' ),
|
||||
'type' => 'text',
|
||||
'description' => __( 'Optionally enable "Payment Data Transfer" (Profile > Profile and Settings > My Selling Tools > Website 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' => '',
|
||||
),
|
||||
'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 unique as PayPal will not allow orders with the same invoice number.', 'woocommerce' ),
|
||||
'default' => 'WC-',
|
||||
'desc_tip' => true,
|
||||
),
|
||||
'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 one address. If you are using PayPal for shipping labels you may prefer to send the shipping address rather than billing. Turning this option off may prevent PayPal Seller protection from applying.', 'woocommerce' ),
|
||||
'default' => 'yes',
|
||||
),
|
||||
'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',
|
||||
),
|
||||
'paymentaction' => array(
|
||||
'title' => __( 'Payment action', 'woocommerce' ),
|
||||
'type' => 'select',
|
||||
'class' => 'wc-enhanced-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' ),
|
||||
),
|
||||
),
|
||||
'image_url' => array(
|
||||
'title' => __( 'Image url', 'woocommerce' ),
|
||||
'type' => 'text',
|
||||
'description' => __( 'Optionally enter the URL to a 150x50px image displayed as your logo in the upper left corner of the PayPal checkout pages.', 'woocommerce' ),
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'placeholder' => __( 'Optional', 'woocommerce' ),
|
||||
),
|
||||
'api_details' => array(
|
||||
'title' => __( 'API credentials', 'woocommerce' ),
|
||||
'type' => 'title',
|
||||
/* translators: %s: URL */
|
||||
'description' => sprintf( __( 'Enter your PayPal API credentials to process refunds via PayPal. Learn how to access your <a href="%s">PayPal API Credentials</a>.', 'woocommerce' ), 'https://developer.paypal.com/webapps/developer/docs/classic/api/apiCredentials/#create-an-api-signature' ),
|
||||
),
|
||||
'api_username' => array(
|
||||
'title' => __( 'Live API username', 'woocommerce' ),
|
||||
'type' => 'text',
|
||||
'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'placeholder' => __( 'Optional', 'woocommerce' ),
|
||||
),
|
||||
'api_password' => array(
|
||||
'title' => __( 'Live API password', 'woocommerce' ),
|
||||
'type' => 'password',
|
||||
'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'placeholder' => __( 'Optional', 'woocommerce' ),
|
||||
),
|
||||
'api_signature' => array(
|
||||
'title' => __( 'Live API signature', 'woocommerce' ),
|
||||
'type' => 'password',
|
||||
'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'placeholder' => __( 'Optional', 'woocommerce' ),
|
||||
),
|
||||
'sandbox_api_username' => array(
|
||||
'title' => __( 'Sandbox API username', 'woocommerce' ),
|
||||
'type' => 'text',
|
||||
'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'placeholder' => __( 'Optional', 'woocommerce' ),
|
||||
),
|
||||
'sandbox_api_password' => array(
|
||||
'title' => __( 'Sandbox API password', 'woocommerce' ),
|
||||
'type' => 'password',
|
||||
'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'placeholder' => __( 'Optional', 'woocommerce' ),
|
||||
),
|
||||
'sandbox_api_signature' => array(
|
||||
'title' => __( 'Sandbox API signature', 'woocommerce' ),
|
||||
'type' => 'password',
|
||||
'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
|
||||
'default' => '',
|
||||
'desc_tip' => true,
|
||||
'placeholder' => __( 'Optional', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
Reference in New Issue
Block a user