JezK
Edit File: class-cartflows-pro-paypal-gateway-helper.php
<?php /** * Cod Gateway helper functions. * * @package cartflows */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Class Cartflows_Pro_Paypal_Gateway_Helper . */ class Cartflows_Pro_Paypal_Gateway_Helper extends Cartflows_Pro_Gateway { /** * Live API URL. * * @var live_api */ public $live_api = 'https://api-3t.paypal.com/nvp'; /** * Test API URL. * * @var test_api */ public $test_api = 'https://api-3t.sandbox.paypal.com/nvp'; /** * Gateway parameters. * * @var parameters */ public $parameters = array(); /** * Add single parameter. * * @param string $key key. * @param string $value value. */ public function add_parameter( $key, $value ) { $this->parameters[ $key ] = $value; } /** * Add multiple parameters. * * @param array $params parameters. */ public function add_parameters( array $params ) { foreach ( $params as $key => $value ) { $this->add_parameter( $key, $value ); } } /** * Add payment parameters * * @param array $params parameters. * * @since 1.0.0 */ private function add_payment_parameters( array $params ) { foreach ( $params as $key => $value ) { $this->add_parameter( "PAYMENTREQUEST_0_{$key}", $value ); } } /** * Set the method for request * * @param string $method request method param. * * @since 1.0.0 */ public function set_method( $method ) { $this->add_parameter( 'METHOD', $method ); } /** * Update payment params * * @since 1.0.0 * * @param WC_Order $order order object. * @param int $step_id step ID. * @param string $type transaction type. * @param bool $use_deprecated_params whether to use deprecated PayPal?. * @param bool $is_offer_charge is offer charge. * @param int $variation_id variation id. * @param int $input_qty input qty. */ public function add_payment_params( WC_Order $order, $step_id, $type, $use_deprecated_params = false, $is_offer_charge = false, $variation_id = '', $input_qty = '' ) { $calculated_total = 0; $order_subtotal = 0; $item_count = 0; $order_items = array(); $offer_package = array(); if ( true === $is_offer_charge ) { $offer_package = wcf_pro()->utils->get_offer_data( $step_id, $variation_id, $input_qty, $order->get_id() ); if ( $offer_package ) { $order_items[] = array( 'NAME' => $offer_package['name'], 'DESC' => $offer_package['desc'], 'AMT' => $this->round( $offer_package['unit_price_tax'] ), 'QTY' => $offer_package['qty'], 'ITEMURL' => $offer_package['url'], ); $order_subtotal += $offer_package['total_unit_price_amount']; // Update the total if need to replace the main order. Need to update the values to prevent the cart total do not match error. $is_cancal_main_order = get_post_meta( $step_id, 'wcf-replace-main-order', true ); if ( 'yes' === $is_cancal_main_order && $offer_package['cancal_main_order'] ) { $order_subtotal = $offer_package['amount_diff']; $order_items[0]['AMT'] = $offer_package['amount_diff']; } } } else { // Add line items. foreach ( $order->get_items() as $item ) { $product = new WC_Product( $item['product_id'] ); $order_items[] = array( 'NAME' => $product->get_title(), 'DESC' => $this->get_item_description( $item, $product, $is_offer_charge ), 'AMT' => $this->round( $order->get_item_subtotal( $item ) ), 'QTY' => ( ! empty( $item['qty'] ) ) ? absint( $item['qty'] ) : 1, 'ITEMURL' => $product->get_permalink(), ); $order_subtotal += $item['line_total']; } foreach ( $order->get_fees() as $fee ) { $order_items[] = array( 'NAME' => ( $fee['name'] ), 'AMT' => $this->round( $fee['line_total'] ), 'QTY' => 1, ); $order_subtotal += $fee['line_total']; } if ( $order->get_total_discount() > 0 ) { $order_items[] = array( 'NAME' => __( 'Total Discount', 'cartflows-pro' ), 'QTY' => 1, 'AMT' => - $this->round( $order->get_total_discount() ), ); } } if ( true === $is_offer_charge ) { /** Handle paypal data setup for the offers */ /** * Code for reference transaction */ $total_amount = $offer_package['total']; $item_names = array(); foreach ( $order_items as $item ) { $item_names[] = sprintf( '%1$s x %2$s', $item['NAME'], $item['QTY'] ); } $item_count = 0; // Add individual order items. foreach ( $order_items as $item ) { $this->add_litem_params( $item, $item_count ++, $use_deprecated_params ); } if ( $use_deprecated_params ) { $this->add_parameters( array( 'AMT' => $total_amount, 'CURRENCYCODE' => wcf_pro()->wc_common->get_currency( $order ), 'ITEMAMT' => $this->round( $order_subtotal ), 'SHIPPINGAMT' => $offer_package['shipping_fee_tax'], 'INVNUM' => $this->wc_gateway()->get_option( 'invoice_prefix' ) . wcf_pro()->wc_common->get_order_id( $order ) . '_' . $offer_package['step_id'], 'PAYMENTACTION' => $type, 'PAYMENTREQUESTID' => wcf_pro()->wc_common->get_order_id( $order ), 'TAXAMT' => 0, 'CUSTOM' => wp_json_encode( array( '_wcf_order_id' => wcf_pro()->wc_common->get_order_id( $order ), ) ), ) ); } else { $this->add_payment_parameters( array( 'AMT' => $total_amount, 'CURRENCYCODE' => wcf_pro()->wc_common->get_currency( $order ), 'ITEMAMT' => $this->round( $order_subtotal ), 'SHIPPINGAMT' => $offer_package['shipping_fee_tax'], 'INVNUM' => $this->wc_gateway()->get_option( 'invoice_prefix' ) . wcf_pro()->wc_common->get_order_id( $order ) . '_' . $offer_package['step_id'], 'PAYMENTACTION' => $type, 'PAYMENTREQUESTID' => wcf_pro()->wc_common->get_order_id( $order ), 'TAXAMT' => 0, 'CUSTOM' => wp_json_encode( array( '_wcf_order_id' => wcf_pro()->wc_common->get_order_id( $order ), ) ), ) ); } } else { /** Do things for the main order */ if ( $this->skip_line_items( $order, $order_items ) ) { $total_amount = $this->round( $order->get_total() ); // Calculate the total. $calculated_total += $this->round( $order_subtotal + $order->get_cart_tax() ) + $this->round( $order->get_total_shipping() + $order->get_shipping_tax() ); // Calculate order subtotal. if ( $this->price_format( $total_amount ) !== $this->price_format( $calculated_total ) ) { $order_subtotal = $order_subtotal - ( $calculated_total - $total_amount ); } $item_names = array(); foreach ( $order_items as $item ) { $item_names[] = sprintf( '%1$s x %2$s', $item['NAME'], $item['QTY'] ); } // Add line item paramter. $this->add_litem_params( array( // translators: placeholder is blogname. 'NAME' => sprintf( __( '%s - Order', 'cartflows-pro' ), get_option( 'blogname' ) ), 'DESC' => ( implode( ', ', $item_names ) ), 'AMT' => $this->round( $order_subtotal + $order->get_cart_tax() ), 'QTY' => 1, ), 0, $use_deprecated_params ); if ( $use_deprecated_params ) { $this->add_parameters( array( 'AMT' => $total_amount, 'CURRENCYCODE' => wcf_pro()->wc_common->get_currency( $order ), 'ITEMAMT' => $this->round( $order_subtotal + $order->get_cart_tax() ), 'SHIPPINGAMT' => $this->round( $order->get_total_shipping() + $order->get_shipping_tax() ), 'INVNUM' => $this->wc_gateway()->get_option( 'invoice_prefix' ) . wcf_pro()->wc_common->get_order_id( $order ), 'PAYMENTACTION' => $type, 'PAYMENTREQUESTID' => wcf_pro()->wc_common->get_order_id( $order ), 'CUSTOM' => wp_json_encode( array( '_wcf_order_id' => wcf_pro()->wc_common->get_order_id( $order ), ) ), ) ); } else { $this->add_payment_parameters( array( 'AMT' => $total_amount, 'CURRENCYCODE' => wcf_pro()->wc_common->get_currency( $order ), 'ITEMAMT' => $this->round( $order_subtotal + $order->get_cart_tax() ), 'SHIPPINGAMT' => $this->round( $order->get_total_shipping() + $order->get_shipping_tax() ), 'INVNUM' => $this->wc_gateway()->get_option( 'invoice_prefix' ) . wcf_pro()->wc_common->get_order_id( $order ), 'PAYMENTACTION' => $type, 'PAYMENTREQUESTID' => wcf_pro()->wc_common->get_order_id( $order ), 'CUSTOM' => wp_json_encode( array( '_wcf_order_id' => wcf_pro()->wc_common->get_order_id( $order ), ) ), ) ); } } else { // Add individual order items. foreach ( $order_items as $item ) { $this->add_litem_params( $item, $item_count ++, $use_deprecated_params ); } $total_amount = $this->round( $order->get_total() ); // Add order-level parameters. if ( $use_deprecated_params ) { $this->add_parameters( array( 'AMT' => $total_amount, 'CURRENCYCODE' => wcf_pro()->wc_common->get_currency( $order ), 'ITEMAMT' => $this->round( $order_subtotal ), 'SHIPPINGAMT' => $this->round( $order->get_total_shipping() ), 'TAXAMT' => $this->round( $order->get_total_tax() ), 'INVNUM' => $this->wc_gateway()->get_option( 'invoice_prefix' ) . wcf_pro()->wc_common->get_order_id( $order ), 'PAYMENTACTION' => $type, 'PAYMENTREQUESTID' => wcf_pro()->wc_common->get_order_id( $order ), ) ); } else { $this->add_payment_parameters( array( 'AMT' => $total_amount, 'CURRENCYCODE' => wcf_pro()->wc_common->get_currency( $order ), 'ITEMAMT' => $this->round( $order_subtotal ), 'SHIPPINGAMT' => $this->round( $order->get_total_shipping() ), 'TAXAMT' => $this->round( $order->get_total_tax() ), 'INVNUM' => $this->wc_gateway()->get_option( 'invoice_prefix' ) . wcf_pro()->wc_common->get_order_id( $order ), 'PAYMENTACTION' => $type, 'PAYMENTREQUESTID' => wcf_pro()->wc_common->get_order_id( $order ), 'CUSTOM' => wp_json_encode( array( '_wcf_order_id' => wcf_pro()->wc_common->get_order_id( $order ), ) ), ) ); } } } } /** * Adds a line item parameters to the request * * @param array $params paramters. * @param int $item_count current item count. * @param bool $use_deprecated_params whether to use deprecated PayPal?. * @since 1.0.0 */ public function add_litem_params( array $params, $item_count, $use_deprecated_params = false ) { foreach ( $params as $key => $value ) { if ( $use_deprecated_params ) { $this->add_parameter( "L_{$key}{$item_count}", $value ); } else { $this->add_parameter( "L_PAYMENTREQUEST_0_{$key}{$item_count}", $value ); } } } /** * Skip line items and send as single item * * @since 1.0.0 * * @param WC_Order $order Optional. The WC_Order object. Default null. * @param array $order_items Order items. * * @return bool true if line items should be skipped, false otherwise */ public function skip_line_items( $order = null, $order_items = null ) { $skip_line_items = false; if ( true != $skip_line_items && ! is_null( $order ) && ! is_null( $order_items ) ) { $calculated_total = 0; foreach ( $order_items as $item ) { $calculated_total += $this->round( $item['AMT'] * $item['QTY'] ); } $calculated_total += $this->round( $order->get_total_shipping() ) + $this->round( $order->get_total_tax() ); $total_amount = $this->round( $order->get_total() ); if ( $this->price_format( $total_amount ) !== $this->price_format( $calculated_total ) ) { $skip_line_items = true; } } // Filter for line items. return apply_filters( 'wcs_paypal_reference_transaction_skip_line_items', $skip_line_items, $order ); } /** * Convert parameter array to HTTP build string * * @return string */ public function to_string() { wcf()->logger->log( wcf_print_r( $this->get_parameters(), true ) ); return http_build_query( $this->get_parameters(), '', '&' ); } /** * Get payment parameters. * * @return array * @throws Exception Paramter errors. */ public function get_parameters() { /** * Filter PPE request parameters. * * Use this to modify the PayPal request parameters prior to validation * * @param array $parameters * @param Cartflows_Pro_Paypal_Gateway_Helper $instance Class instance */ $instance = new Cartflows_Pro_Paypal_Gateway_Helper(); $this->parameters = apply_filters( 'wcs_paypal_request_params', $this->parameters, $instance ); // validate parameters. foreach ( $this->parameters as $key => $value ) { // remove unused params. if ( '' === $value || is_null( $value ) ) { unset( $this->parameters[ $key ] ); } // format and check amounts. if ( false !== strpos( $key, 'AMT' ) ) { // amounts must be 10,000.00 or less for USD. if ( isset( $this->parameters['PAYMENTREQUEST_0_CURRENCYCODE'] ) && 'USD' == $this->parameters['PAYMENTREQUEST_0_CURRENCYCODE'] && $value > 10000 ) { throw new Exception( sprintf( '%s amount of %s must be less than $10,000.00', $key, $value ) ); } $this->parameters[ $key ] = $this->price_format( $value ); } } return $this->parameters; } /** * Check if api response has error * * @param array $response response object array. * @return bool */ public function has_error_api_response( $response ) { // Consider error when ACK parameter is missing. if ( ! isset( $response['ACK'] ) ) { return true; } // Check if response contains success string. return ( 'Success' !== $this->get_value_from_response( $response, 'ACK' ) && 'SuccessWithWarning' !== $this->get_value_from_response( $response, 'ACK' ) ); } /** * Set variables for API calls * * @param int $gateway_id gateway ID. * @param string $api_env Api enviornment. * @param string $api_usr API username. * @param string $api_pass API password. * @param string $api_sign API signature. */ public function setup_api_vars( $gateway_id, $api_env, $api_usr, $api_pass, $api_sign ) { $this->api_username = $api_usr; $this->api_password = $api_pass; $this->api_signature = $api_sign; $this->gateway_id = $gateway_id; // Rquest URI per enviornment. $this->request_uri = ( 'live' === $api_env ) ? $this->live_api : $this->test_api; // Set HTTP version to 1.1. $this->request_http_version = '1.1'; } /** * Add api credentials parameters * * @param string $api_username API username. * @param string $api_password API password. * @param string $api_signature API signature. * @param string $api_version API version. * @return void */ public function add_credentials_param( $api_username, $api_password, $api_signature, $api_version ) { $this->add_parameters( array( 'USER' => $api_username, 'PWD' => $api_password, 'SIGNATURE' => $api_signature, 'VERSION' => $api_version, ) ); } }