Skip to content

Instantly share code, notes, and snippets.

@luiseduardobraschi
Created March 15, 2024 04:43
Show Gist options
  • Save luiseduardobraschi/a82291ef481c695b91b593a9a4b80fdd to your computer and use it in GitHub Desktop.
Save luiseduardobraschi/a82291ef481c695b91b593a9a4b80fdd to your computer and use it in GitHub Desktop.
Atualização de status plugin Pagar.me - Cláudio Sanches
<?php
/**
* Pagar.me API
*
* @package WooCommerce_Pagarme/API
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WC_Pagarme_API class.
*/
class WC_Pagarme_API {
/**
* API URL.
*/
const API_URL = 'https://api.pagar.me/1/';
/**
* Gateway class.
*
* @var WC_Payment_Gateway
*/
protected $gateway;
/**
* API URL.
*
* @var string
*/
protected $api_url = 'https://api.pagar.me/1/';
/**
* JS Library URL.
*
* @var string
*/
protected $js_url = 'https://assets.pagar.me/js/pagarme.min.js';
/**
* Checkout JS Library URL.
*
* @var string
*/
protected $checkout_js_url = 'https://assets.pagar.me/checkout/checkout.js';
/**
* Constructor.
*
* @param WC_Payment_Gateway $gateway Gateway instance.
*/
public function __construct( $gateway = null ) {
$this->gateway = $gateway;
}
/**
* Get API URL.
*
* @return string
*/
public function get_api_url() {
return $this->api_url;
}
/**
* Get JS Library URL.
*
* @return string
*/
public function get_js_url() {
return $this->js_url;
}
/**
* Get Checkout JS Library URL.
*
* @return string
*/
public function get_checkout_js_url() {
return $this->checkout_js_url;
}
/**
* Returns a bool that indicates if currency is amongst the supported ones.
*
* @return bool
*/
public function using_supported_currency() {
return 'BRL' === get_woocommerce_currency();
}
/**
* Only numbers.
*
* @param string|int $string String to convert.
*
* @return string|int
*/
protected function only_numbers( $string ) {
return preg_replace( '([^0-9])', '', $string );
}
/**
* Get the smallest installment amount.
*
* @return int
*/
public function get_smallest_installment() {
return ( 5 > $this->gateway->smallest_installment ) ? 500 : wc_format_decimal( $this->gateway->smallest_installment ) * 100;
}
/**
* Get the interest rate.
*
* @return float
*/
public function get_interest_rate() {
return wc_format_decimal( $this->gateway->interest_rate );
}
/**
* Do requests in the Pagar.me API.
*
* @param string $endpoint API Endpoint.
* @param string $method Request method.
* @param array $data Request data.
* @param array $headers Request headers.
*
* @return array Request response.
*/
protected function do_request( $endpoint, $method = 'POST', $data = array(), $headers = array() ) {
$params = array(
'method' => $method,
'timeout' => 60,
);
if ( ! empty( $data ) ) {
$params['body'] = $data;
}
// Pagar.me user-agent and api version.
$x_pagarme_useragent = 'pagarme-woocommerce/' . WC_Pagarme::VERSION;
if ( defined( 'WC_VERSION' ) ) {
$x_pagarme_useragent .= ' woocommerce/' . WC_VERSION;
}
$x_pagarme_useragent .= ' wordpress/' . get_bloginfo( 'version' );
$x_pagarme_useragent .= ' php/' . phpversion();
$params['headers'] = [
'User-Agent' => $x_pagarme_useragent,
'X-PagarMe-User-Agent' => $x_pagarme_useragent,
'X-PagarMe-Version' => '2017-07-17',
];
if ( ! empty( $headers ) ) {
$params['headers'] = array_merge( $params['headers'], $headers );
}
return wp_safe_remote_post( $this->get_api_url() . $endpoint, $params );
}
/**
* Get the installments.
*
* @param float $amount Order amount.
*
* @return array
*/
public function get_installments( $amount ) {
// Set the installment data.
$data = array(
'encryption_key' => $this->gateway->encryption_key,
'amount' => $amount * 100,
'interest_rate' => $this->get_interest_rate(),
'max_installments' => $this->gateway->max_installment,
'free_installments' => $this->gateway->free_installments,
);
$transient_id = 'pgi_' . md5( http_build_query( $data ) );
// Get saved installment data.
$_installments = get_transient( $transient_id );
if ( false !== $_installments ) {
return $_installments;
}
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Getting the order installments...' );
}
$response = $this->do_request( 'transactions/calculate_installments_amount', 'GET', $data );
if ( is_wp_error( $response ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'WP_Error in getting the installments: ' . $response->get_error_message() );
}
return array();
} else {
$_installments = json_decode( $response['body'], true );
if ( isset( $_installments['installments'] ) ) {
$installments = $_installments['installments'];
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Installments generated successfully: ' . print_r( $_installments, true ) );
}
set_transient( $transient_id, $installments, MINUTE_IN_SECONDS * 5 );
return $installments;
}
}
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Failed to get the installments: ' . print_r( $response, true ) );
}
return array();
}
/**
* Get max installment.
*
* @param float $amount Order amount.
*
* @return int
*/
public function get_max_installment( $amount ) {
$installments = $this->get_installments( $amount );
$smallest_installment = $this->get_smallest_installment();
$max = 1;
foreach ( $installments as $number => $installment ) {
if ( $smallest_installment > $installment['installment_amount'] ) {
break;
}
$max = $number;
}
return $max;
}
/**
* Generate the transaction data.
*
* @param WC_Order $order Order data.
* @param array $posted Form posted data.
*
* @return array Transaction data.
*/
public function generate_transaction_data( $order, $posted ) {
// Set the request data.
$data = array(
'api_key' => $this->gateway->api_key,
'amount' => $order->get_total() * 100,
'postback_url' => WC()->api_request_url( get_class( $this->gateway ) ),
'customer' => array(
'name' => trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() ),
'email' => $order->get_billing_email(),
),
'metadata' => array(
'order_number' => $order->get_order_number(),
),
);
// Phone.
if ( ! empty( $order->get_billing_phone() ) ) {
$phone = $this->only_numbers( $order->get_billing_phone() );
$data['customer']['phone'] = array(
'ddd' => substr( $phone, 0, 2 ),
'number' => substr( $phone, 2 ),
);
}
// Address.
if ( ! empty( $order->get_billing_address_1() ) ) {
$data['customer']['address'] = array(
'street' => $order->get_billing_address_1(),
'complementary' => $order->get_billing_address_2(),
'zipcode' => $this->only_numbers( $order->get_billing_postcode() ),
);
// Non-WooCommerce default address fields.
if ( ! empty( $order->get_meta( '_billing_number' ) ) ) {
$data['customer']['address']['street_number'] = $order->get_meta( '_billing_number' );
}
if ( ! empty( $order->get_meta( '_billing_neighborhood' ) ) ) {
$data['customer']['address']['neighborhood'] = $order->get_meta( '_billing_neighborhood' );
}
}
// Set the document number.
if ( class_exists( 'Extra_Checkout_Fields_For_Brazil' ) ) {
$wcbcf_settings = get_option( 'wcbcf_settings' );
$person_type = (string) $wcbcf_settings['person_type'];
if ( '0' !== $person_type ) {
if ( ( '1' === $person_type && '1' === $order->get_meta( '_billing_persontype' ) ) || '2' === $person_type ) {
$data['customer']['document_number'] = $this->only_numbers( $order->get_meta( '_billing_cpf' ) );
}
if ( ( '1' === $person_type && '2' === $order->get_meta( '_billing_persontype' ) ) || '3' === $person_type ) {
$data['customer']['name'] = $order->get_billing_company();
$data['customer']['document_number'] = $this->only_numbers( $order->get_meta( '_billing_cnpj' ) );
}
}
} else {
if ( ! empty( $order->get_meta( '_billing_cpf' ) ) ) {
$data['customer']['document_number'] = $this->only_numbers( $order->get_meta( '_billing_cpf' ) );
}
if ( ! empty( $order->get_meta( '_billing_cnpj' ) ) ) {
$data['customer']['name'] = $order->get_billing_company();
$data['customer']['document_number'] = $this->only_numbers( $order->get_meta( '_billing_cnpj' ) );
}
}
// Set the customer gender.
if ( ! empty( $order->get_meta( '_billing_sex' ) ) ) {
$data['customer']['sex'] = strtoupper( substr( $order->get_meta( '_billing_sex' ), 0, 1 ) );
}
// Set the customer birthdate.
if ( ! empty( $order->get_meta( '_billing__billing_birthdate' ) ) ) {
$birthdate = explode( '/', $order->get_meta( '_billing__billing_birthdate' ) );
$data['customer']['born_at'] = $birthdate[1] . '-' . $birthdate[0] . '-' . $birthdate[2];
}
if ( 'pagarme-credit-card' === $this->gateway->id ) {
if ( isset( $posted['pagarme_card_hash'] ) ) {
$data['payment_method'] = 'credit_card';
$data['card_hash'] = $posted['pagarme_card_hash'];
}
$is_checkout_pagarme = isset( $this->gateway->checkout ) && 'yes' === $this->gateway->checkout;
$has_installment_data = ! empty( $posted['pagarme_installments'] ) && isset( $posted['pagarme_installments'] );
$should_set_default_installment = $is_checkout_pagarme && ! $has_installment_data;
$_installment = $should_set_default_installment ? 1 : $posted['pagarme_installments'];
// Validate the installments.
$data['installments'] = $_installment;
// Get installments data.
$installments = $this->get_installments( $order->get_total() );
if ( isset( $installments[ $_installment ] ) ) {
$installment = $installments[ $_installment ];
$smallest_installment = $this->get_smallest_installment();
if ( $installment['installment'] <= $this->gateway->max_installment && $smallest_installment <= $installment['installment_amount'] ) {
$data['amount'] = $installment['amount'];
}
}
} elseif ( 'pagarme-banking-ticket' === $this->gateway->id ) {
$data['payment_method'] = 'boleto';
$data['async'] = 'yes' === $this->gateway->async;
}
// Add filter for Third Party plugins.
return apply_filters( 'wc_pagarme_transaction_data', $data , $order );
}
/**
* Get customer data from checkout pay page.
*
* @return array
*/
public function get_customer_data_from_checkout_pay_page() {
global $wp;
$order = wc_get_order( (int) $wp->query_vars['order-pay'] );
$data = $this->generate_transaction_data( $order, array() );
$customer = array();
if ( empty( $data['customer'] ) ) {
return $customer;
}
$_customer = $data['customer'];
$customer['customerName'] = $_customer['name'];
$customer['customerEmail'] = $_customer['email'];
if ( isset( $_customer['document_number'] ) ) {
$customer['customerDocumentNumber'] = $_customer['document_number'];
}
if ( isset( $_customer['address'] ) ) {
$customer['customerAddressStreet'] = $_customer['address']['street'];
$customer['customerAddressComplementary'] = $_customer['address']['complementary'];
$customer['customerAddressZipcode'] = $_customer['address']['zipcode'];
if ( isset( $_customer['address']['street_number'] ) ) {
$customer['customerAddressStreetNumber'] = $_customer['address']['street_number'];
}
if ( isset( $_customer['address']['neighborhood'] ) ) {
$customer['customerAddressNeighborhood'] = $_customer['address']['neighborhood'];
}
}
if ( isset( $_customer['phone'] ) ) {
$customer['customerPhoneDdd'] = $_customer['phone']['ddd'];
$customer['customerPhoneNumber'] = $_customer['phone']['number'];
}
return $customer;
}
/**
* Get transaction data.
*
* @param WC_Order $order Order data.
* @param string $token Checkout token.
*
* @return array Response data.
*/
public function get_transaction_data( $order, $token ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Getting transaction data for order ' . $order->get_order_number() . '...' );
}
$response = $this->do_request( 'transactions/' . $token, 'GET', array( 'api_key' => $this->gateway->api_key ) );
if ( is_wp_error( $response ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'WP_Error in getting transaction data: ' . $response->get_error_message() );
}
return array();
} else {
$data = json_decode( $response['body'], true );
if ( isset( $data['errors'] ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Failed to get transaction data: ' . print_r( $response, true ) );
}
return $data;
}
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Transaction data obtained successfully!' );
}
return $data;
}
}
/**
* Generate checkout data.
*
* @param WC_Order $order Order data.
* @param string $token Checkout token.
*
* @return array Checkout data.
*/
public function generate_checkout_data( $order, $token ) {
$transaction = $this->get_transaction_data( $order, $token );
$installments = $this->get_installments( $order->get_total() );
// Valid transaction.
if ( ! isset( $transaction['amount'] ) ) {
return array( 'error' => __( 'Invalid transaction data.', 'woocommerce-pagarme' ) );
}
// Test if using more installments that allowed.
if ( $this->gateway->max_installment < $transaction['installments'] || empty( $installments[ $transaction['installments'] ] ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Payment made with more installments than allowed for order ' . $order->get_order_number() );
}
return array( 'error' => __( 'Payment made with more installments than allowed.', 'woocommerce-pagarme' ) );
}
$installment = $installments[ $transaction['installments'] ];
// Test smallest installment amount.
if ( 1 !== intval( $transaction['installments'] ) && $this->get_smallest_installment() > $installment['installment_amount'] ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Payment divided into a lower amount than permitted for order ' . $order->get_order_number() );
}
return array( 'error' => __( 'Payment divided into a lower amount than permitted.', 'woocommerce-pagarme' ) );
}
// Check the transaction amount.
if ( intval( $transaction['amount'] ) !== intval( $installment['amount'] ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Wrong payment amount total for order ' . $order->get_order_number() );
}
return array( 'error' => __( 'Wrong payment amount total.', 'woocommerce-pagarme' ) );
}
$data = array(
'api_key' => $this->gateway->api_key,
'amount' => $transaction['amount'],
'metadata' => array(
'order_number' => $order->get_order_number(),
),
);
return apply_filters( 'wc_pagarme_checkout_data', $data );
}
/**
* Do the transaction.
*
* @param WC_Order $order Order data.
* @param array $args Transaction args.
* @param string $token Checkout token.
*
* @return array Response data.
*/
public function do_transaction( $order, $args, $token = '' ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Doing a transaction for order ' . $order->get_order_number() . '...' );
}
$endpoint = 'transactions';
if ( ! empty( $token ) ) {
$endpoint .= '/' . $token . '/capture';
}
$response = $this->do_request( $endpoint, 'POST', $args );
if ( is_wp_error( $response ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'WP_Error in doing the transaction: ' . $response->get_error_message() );
}
return array();
} else {
$data = json_decode( $response['body'], true );
if ( isset( $data['errors'] ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Failed to make the transaction: ' . print_r( $response, true ) );
}
return $data;
}
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Transaction completed successfully! The transaction response is: ' . print_r( $data, true ) );
}
return $data;
}
}
/**
* Refund the order.
*
* @param WC_Order $order Order data.
* @param float $amount Amount to refund.
*
* @return bool Successfully refunded.
*/
public function do_refund( $order_id, $amount ) {
$order = wc_get_order( $order_id );
$transaction_id = get_post_meta( $order_id, '_wc_pagarme_transaction_id', true );
$endpoint = 'transactions/' . $transaction_id . '/refund';
$data = array (
'api_key' => $this->gateway->api_key,
);
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Starting refunding for order. ID: ' . $order->get_order_number() . '...' );
}
if ( ! in_array( $order->get_status(), array( 'processing', 'completed' ), true ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Can\'t refund unpaid order. ID: ' . $order->get_order_number() );
}
return false;
}
if ( $order->get_total() < $amount ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Can\'t refund more than the paid amount. ID: ' . $order->get_order_number() );
}
return false;
}
if ( $amount <= 0 ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Can\'t refund when amount is zero or negative. ID: ' . $order->get_order_number() );
}
return false;
}
$is_partially_refund = $amount < $order->get_total();
if ( $is_partially_refund ){
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Refunding order partially. ID: ' . $order->get_order_number() . '...' );
$this->gateway->log->add( $this->gateway->id, 'Order total: ' . $order->get_total() . ', Refund total: ' . $amount );
}
$data['amount'] = $amount * 100;
}
$response = $this->do_request( $endpoint, 'POST', $data );
if ( is_wp_error( $response ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Error doing refund: ' . $response->get_error_message() );
}
return false;
}
$response_data = json_decode( $response['body'], true );
if ( isset( $response_data['errors'] ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Failed to make the refund: ' . print_r( $response, true ) );
}
return false;
}
return true;
}
/**
* Do the transaction.
*
* @param WC_Order $order Order data.
* @param string $token Checkout token.
*
* @return array Response data.
*/
public function cancel_transaction( $order, $token ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Cancelling transaction for order ' . $order->get_order_number() . '...' );
}
$endpoint = 'transactions';
if ( ! empty( $token ) ) {
$endpoint .= '/' . $token . '/refund';
}
$response = $this->do_request( $endpoint, 'POST', array( 'api_key' => $this->gateway->api_key ) );
if ( is_wp_error( $response ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'WP_Error in doing the transaction cancellation: ' . $response->get_error_message() );
}
return array();
} else {
$data = json_decode( $response['body'], true );
if ( isset( $data['errors'] ) ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Failed to cancel the transaction: ' . print_r( $response, true ) );
}
return $data;
}
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Transaction canceled successfully! The response is: ' . print_r( $data, true ) );
}
return $data;
}
}
/**
* Get card brand name.
*
* @param string $brand Card brand.
* @return string
*/
protected function get_card_brand_name( $brand ) {
$names = array(
'visa' => __( 'Visa', 'woocommerce-pagarme' ),
'mastercard' => __( 'MasterCard', 'woocommerce-pagarme' ),
'amex' => __( 'American Express', 'woocommerce-pagarme' ),
'aura' => __( 'Aura', 'woocommerce-pagarme' ),
'jcb' => __( 'JCB', 'woocommerce-pagarme' ),
'diners' => __( 'Diners', 'woocommerce-pagarme' ),
'elo' => __( 'Elo', 'woocommerce-pagarme' ),
'hipercard' => __( 'Hipercard', 'woocommerce-pagarme' ),
'discover' => __( 'Discover', 'woocommerce-pagarme' ),
);
return isset( $names[ $brand ] ) ? $names[ $brand ] : $brand;
}
/**
* Save order meta fields.
* Save fields as meta data to display on order's admin screen.
*
* @param int $id Order ID.
* @param array $data Order data.
*/
protected function save_order_meta_fields( $id, $data ) {
// Transaction data.
$payment_data = array_map(
'sanitize_text_field',
array(
'payment_method' => $data['payment_method'],
'installments' => $data['installments'],
'card_brand' => $this->get_card_brand_name( $data['card_brand'] ),
'antifraud_score' => $data['antifraud_score'],
'boleto_url' => $data['boleto_url'],
)
);
// Meta data.
$meta_data = array(
__( 'Banking Ticket URL', 'woocommerce-pagarme' ) => sanitize_text_field( $data['boleto_url'] ),
__( 'Credit Card', 'woocommerce-pagarme' ) => $this->get_card_brand_name( sanitize_text_field( $data['card_brand'] ) ),
__( 'Installments', 'woocommerce-pagarme' ) => sanitize_text_field( $data['installments'] ),
__( 'Total paid', 'woocommerce-pagarme' ) => number_format( intval( $data['amount'] ) / 100, wc_get_price_decimals(), wc_get_price_decimal_separator(), wc_get_price_thousand_separator() ),
__( 'Anti Fraud Score', 'woocommerce-pagarme' ) => sanitize_text_field( $data['antifraud_score'] ),
'_wc_pagarme_transaction_data' => $payment_data,
'_wc_pagarme_transaction_id' => intval( $data['id'] ),
'_transaction_id' => intval( $data['id'] ),
);
$order = wc_get_order( $id );
// WooCommerce 3.0 or later.
if ( ! method_exists( $order, 'update_meta_data' ) ) {
foreach ( $meta_data as $key => $value ) {
update_post_meta( $id, $key, $value );
}
} else {
foreach ( $meta_data as $key => $value ) {
$order->update_meta_data( $key, $value );
}
$order->save();
}
}
/**
* Process regular payment.
*
* @param int $order_id Order ID.
*
* @return array Redirect data.
*/
public function process_regular_payment( $order_id ) {
$order = wc_get_order( $order_id );
$is_checkout_pagarme = isset( $this->gateway->checkout ) && 'yes' === $this->gateway->checkout;
$register_refused_order = isset( $this->gateway->register_refused_order ) && 'yes' === $this->gateway->register_refused_order;
if ( $is_checkout_pagarme && ! $register_refused_order ) {
if ( ! empty( $_POST['pagarme_checkout_token'] ) ) {
$token = sanitize_text_field( wp_unslash( $_POST['pagarme_checkout_token'] ) );
$data = $this->generate_checkout_data( $order, $token );
// Cancel the payment is irregular.
if ( isset( $data['error'] ) ) {
$this->cancel_transaction( $order, $token );
$order->update_status( 'failed', $data['error'] );
return array(
'result' => 'success',
'redirect' => $this->gateway->get_return_url( $order ),
);
}
$transaction = $this->do_transaction( $order, $data, $token );
} else {
$transaction = array( 'errors' => array( array( 'message' => __( 'Missing credit card data, please review your data and try again or contact us for assistance.', 'woocommerce-pagarme' ) ) ) );
}
} else {
$data = $this->generate_transaction_data( $order, $_POST );
$transaction = $this->do_transaction( $order, $data );
}
if ( isset( $transaction['errors'] ) ) {
foreach ( $transaction['errors'] as $error ) {
wc_add_notice( $error['message'], 'error' );
}
return array(
'result' => 'fail',
);
} else {
$this->save_order_meta_fields( $order_id, $transaction );
$this->process_order_status( $order, $transaction['status'] );
// Empty the cart.
WC()->cart->empty_cart();
// Redirect to thanks page.
return array(
'result' => 'success',
'redirect' => $this->gateway->get_return_url( $order ),
);
}
}
/**
* Check if Pagar.me response is validity.
*
* @param array $ipn_response IPN response data.
*
* @return bool
*/
public function check_fingerprint( $ipn_response ) {
$signature = $_SERVER['HTTP_X_HUB_SIGNATURE'];
$parts = explode('=', $signature, 2);
if (count($parts) != 2) {
return false;
}
$api_key = $this->gateway->api_key;
$hash = hash_hmac($parts[0], $ipn_response, $api_key);
$log = [];
$log['parts'] = $parts;
$log['hash'] = $hash;
$log['ipn_response'] = $ipn_response;
return $hash === $parts[1];
}
/**
* Send email notification.
*
* @param string $subject Email subject.
* @param string $title Email title.
* @param string $message Email message.
*/
protected function send_email( $subject, $title, $message ) {
$mailer = WC()->mailer();
$mailer->send( get_option( 'admin_email' ), $subject, $mailer->wrap_message( $title, $message ) );
}
/**
* IPN handler.
*/
public function ipn_handler() {
@ob_clean();
$ipn_response = file_get_contents('php://input');
if ( $ipn_response && $this->check_fingerprint( $ipn_response ) ) {
header( 'HTTP/1.1 200 OK' );
parse_str( $ipn_response, $parsed_ipn_response );
$this->process_successful_ipn( $parsed_ipn_response );
// Deprecated action since 2.0.0.
do_action( 'wc_pagarme_valid_ipn_request', $ipn_response );
exit;
} else {
wp_die( esc_html__( 'Pagar.me Request Failure', 'woocommerce-pagarme' ), '', array( 'response' => 401 ) );
}
}
/**
* Process successeful IPN requests.
*
* @param array $posted Posted data.
*/
public function process_successful_ipn( $posted ) {
global $wpdb;
$posted = wp_unslash( $posted );
$order_id = absint( $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wc_pagarme_transaction_id' AND meta_value = %d", $posted['id'] ) ) );
$order = wc_get_order( $order_id );
$status = sanitize_text_field( $posted['current_status'] );
if ( $order && $order->id === $order_id ) {
$this->process_order_status( $order, $status );
}
// Async transactions will only send the boleto_url on IPN.
if ( ! empty( $posted['transaction']['boleto_url'] ) && 'pagarme-banking-ticket' === $order->payment_method ) {
$post_data = get_post_meta( $order->id, '_wc_pagarme_transaction_data', true );
$post_data['boleto_url'] = sanitize_text_field( $posted['transaction']['boleto_url'] );
update_post_meta( $order->id, '_wc_pagarme_transaction_data', $post_data );
}
}
/**
* Process the order status.
*
* @param WC_Order $order Order data.
* @param string $status Transaction status.
*/
public function process_order_status( $order, $status ) {
if ( 'yes' === $this->gateway->debug ) {
$this->gateway->log->add( $this->gateway->id, 'Payment status for order ' . $order->get_order_number() . ' is now: ' . $status );
}
switch ( $status ) {
case 'authorized' :
if ( ! in_array( $order->get_status(), array( 'processing', 'completed' ), true ) ) {
$order->update_status( 'on-hold', __( 'Pagar.me: The transaction was authorized.', 'woocommerce-pagarme' ) );
}
break;
case 'pending_review':
$transaction_id = get_post_meta( $order->id, '_wc_pagarme_transaction_id', true );
$transaction_url = '<a href="https://dashboard.pagar.me/#/transactions/' . intval( $transaction_id ) . '">https://dashboard.pagar.me/#/transactions/' . intval( $transaction_id ) . '</a>';
/* translators: %s transaction details url */
$order->update_status( 'on-hold', __( 'Pagar.me: You should manually analyze this transaction to continue payment flow, access %s to do it!', 'woocommerce-pagarme' ), $transaction_url );
break;
case 'processing' :
$order->update_status( 'on-hold', __( 'Pagar.me: The transaction is being processed.', 'woocommerce-pagarme' ) );
break;
case 'paid' :
if ( ! in_array( $order->get_status(), array( 'processing', 'completed' ), true ) ) {
$order->add_order_note( __( 'Pagar.me: Transaction paid.', 'woocommerce-pagarme' ) );
}
// Changing the order for processing and reduces the stock.
$order->payment_complete();
break;
case 'waiting_payment' :
$order->update_status( 'on-hold', __( 'Pagar.me: The banking ticket was issued but not paid yet.', 'woocommerce-pagarme' ) );
break;
case 'refused' :
$order->update_status( 'failed', __( 'Pagar.me: The transaction was rejected by the card company or by fraud.', 'woocommerce-pagarme' ) );
$transaction_id = get_post_meta( $order->id, '_wc_pagarme_transaction_id', true );
$transaction_url = '<a href="https://dashboard.pagar.me/#/transactions/' . intval( $transaction_id ) . '">https://dashboard.pagar.me/#/transactions/' . intval( $transaction_id ) . '</a>';
$this->send_email(
sprintf( esc_html__( 'The transaction for order %s was rejected by the card company or by fraud', 'woocommerce-pagarme' ), $order->get_order_number() ),
esc_html__( 'Transaction failed', 'woocommerce-pagarme' ),
sprintf( esc_html__( 'Order %1$s has been marked as failed, because the transaction was rejected by the card company or by fraud, for more details, see %2$s.', 'woocommerce-pagarme' ), $order->get_order_number(), $transaction_url )
);
break;
case 'refunded' :
$order->update_status( 'refunded', __( 'Pagar.me: The transaction was refunded/canceled.', 'woocommerce-pagarme' ) );
$transaction_id = get_post_meta( $order->id, '_wc_pagarme_transaction_id', true );
$transaction_url = '<a href="https://dashboard.pagar.me/#/transactions/' . intval( $transaction_id ) . '">https://dashboard.pagar.me/#/transactions/' . intval( $transaction_id ) . '</a>';
$this->send_email(
sprintf( esc_html__( 'The transaction for order %s refunded', 'woocommerce-pagarme' ), $order->get_order_number() ),
esc_html__( 'Transaction refunded', 'woocommerce-pagarme' ),
sprintf( esc_html__( 'Order %1$s has been marked as refunded by Pagar.me, for more details, see %2$s.', 'woocommerce-pagarme' ), $order->get_order_number(), $transaction_url )
);
break;
case 'analyzing' :
$order->update_status( 'on-hold', __( 'Pagar.me: Transaction is waiting for antifraud analysis.', 'woocommerce-pagarme' ) );
break;
default :
break;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment