Plugin Directory

Changeset 3216172


Ignore:
Timestamp:
01/03/2025 12:30:32 AM (3 months ago)
Author:
nofraud
Message:

4.5.5

Location:
nofraud-protection/trunk
Files:
1 added
11 edited

Legend:

Unmodified
Added
Removed
  • nofraud-protection/trunk/api/class-api.php

    r3192579 r3216172  
    1010use WooCommerce\NoFraud\Common\Database;
    1111use WooCommerce\NoFraud\Payment\Transactions\Transaction_Scheduler;
     12use WooCommerce\NoFraud\Payment\Transactions\Transaction_Manager;
    1213use WooCommerce\NoFraud\Payment\Transactions\Constants;
    1314
     
    2728                    'callback' => [ get_called_class(), 'transactions_refresh' ],
    2829                ));
     30
     31                register_rest_route( 'nf', '/transactions/reprocess/run/(?P<startdate>[0-9-]+)/(?P<enddate>[0-9-]+)/', [
     32                    'methods'  => 'GET',
     33                    'callback' => [ get_called_class(), 'reprocess_transactions_run' ],
     34                    'args'     => [
     35                        'startdate' => [
     36                            'required'          => true,
     37                            'validate_callback' => function ($param, $request, $key) {
     38                                // Validate the MySQL datetime format
     39                                return (bool) preg_match('/^\d{4}-\d{2}-\d{2}$/', $param);
     40                            },
     41                            'sanitize_callback' => 'sanitize_text_field',
     42                            'description'       => 'MySQL datetime string in the format YYYY-MM-DD',
     43                        ],
     44                        'enddate' => [
     45                            'required'          => true,
     46                            'validate_callback' => function ($param, $request, $key) {
     47                                // Validate the MySQL datetime format
     48                                return (bool) preg_match('/^\d{4}-\d{2}-\d{2}$/', $param);
     49                            },
     50                            'sanitize_callback' => 'sanitize_text_field',
     51                            'description'       => 'MySQL datetime string in the format YYYY-MM-DD',
     52                        ],
     53                    ],
     54                    'permission_callback' => '__return_true',
     55                ]);
     56
     57                register_rest_route( 'nf', '/transactions/reprocess/count/(?P<startdate>[0-9-]+)/(?P<enddate>[0-9-]+)/', [
     58                    'methods'  => 'GET',
     59                    'callback' => [ get_called_class(), 'reprocess_transactions_count' ],
     60                    'args'     => [
     61                        'startdate' => [
     62                            'required'          => true,
     63                            'validate_callback' => function ($param, $request, $key) {
     64                                // Validate the MySQL datetime format
     65                                return (bool) preg_match('/^\d{4}-\d{2}-\d{2}$/', $param);
     66                            },
     67                            'sanitize_callback' => 'sanitize_text_field',
     68                            'description'       => 'MySQL datetime string in the format YYYY-MM-DD',
     69                        ],
     70                        'enddate' => [
     71                            'required'          => true,
     72                            'validate_callback' => function ($param, $request, $key) {
     73                                // Validate the MySQL datetime format
     74                                return (bool) preg_match('/^\d{4}-\d{2}-\d{2}$/', $param);
     75                            },
     76                            'sanitize_callback' => 'sanitize_text_field',
     77                            'description'       => 'MySQL datetime string in the format YYYY-MM-DD',
     78                        ],
     79                    ],
     80                    'permission_callback' => '__return_true',
     81                ]);
     82
     83                register_rest_route( 'nf', '/transactions/reprocess/completed/', [
     84                    'methods'  => 'GET',
     85                    'callback' => [ get_called_class(), 'reprocess_transactions_count_completed' ],
     86                    'args'     => [
     87                    ],
     88                    'permission_callback' => '__return_true',
     89                ]);
    2990            });
    3091        }
    3192
    3293        add_action('woocommerce_rest_prepare_shop_order_object', [$instance, 'nf_add_data_to_rest_api'], 10, 3);
     94    }
     95
     96    /**
     97     * Callback function to handle the reprocessing of transactions.
     98     *
     99     * @param WP_REST_Request $request The REST request.
     100     * @return WP_REST_Response The response.
     101     */
     102    public static function reprocess_transactions_run($request) {
     103        $startdate = $request->get_param('startdate');
     104        $enddate = $request->get_param('enddate');
     105
     106        global $wpdb;
     107
     108        $startdate = $request->get_param('startdate') . ' 00:00:00';
     109        $enddate = $request->get_param('enddate') . ' 23:59:59';
     110
     111        // fetch count of all orders placed in this range that are eligible for reprocessing
     112        $nfTransactionsTable = $wpdb->prefix . "nf_transactions";
     113        $wcOrdersTable = $wpdb->prefix . "wc_orders";
     114        $sql = $wpdb->prepare("
     115            SELECT
     116                nft.*
     117            FROM
     118                {$wcOrdersTable} wco
     119            INNER JOIN
     120                {$nfTransactionsTable} nft
     121            ON
     122                (
     123                    nft.meta_value = 'reprocess'
     124                    OR
     125                    nft.meta_value = 'gatewaydisabled'
     126                )
     127                AND           
     128                nft.meta_key = '_nofraud_transaction_review_status'
     129                AND
     130                nft.order_id = wco.id   
     131            WHERE
     132                wco.date_created_gmt <= %s 
     133                AND
     134                wco.date_created_gmt >= %s
     135                AND
     136                wco.status NOT IN ('wc-completed', 'wc-cancelled', 'wc-refunded', 'wc-failed')
     137                AND
     138                wco.type = 'shop_order'
     139        ", $enddate, $startdate);
     140
     141        if ('yes' !== get_option('woocommerce_custom_orders_table_enabled')) {
     142            $wcPostsTable = $wpdb->prefix . "posts";
     143            $sql = $wpdb->prepare("
     144            SELECT
     145                nft.*
     146            FROM
     147                {$wcPostsTable} wpt
     148            INNER JOIN
     149                {$nfTransactionsTable} nft
     150            ON
     151                (
     152                    nft.meta_value = 'reprocess'
     153                    OR
     154                    nft.meta_value = 'gatewaydisabled'
     155                )
     156                AND           
     157                nft.meta_key = '_nofraud_transaction_review_status'
     158                AND
     159                nft.order_id = wpt.id   
     160            WHERE
     161                wpt.post_date_gmt <= %s 
     162                AND
     163                wpt.post_date_gmt >= %s
     164                AND
     165                wpt.post_status NOT IN ('wc-completed', 'wc-cancelled', 'wc-refunded', 'wc-failed')
     166                AND
     167                wpt.post_type = 'shop_order'
     168        ", $enddate, $startdate);
     169        }
     170
     171        $results = $wpdb->get_results($sql, ARRAY_A);
     172
     173        $count = 0;
     174        if ($results === null) {
     175            $response_data = [
     176                'message'  => 'Error encountered running reprocessing',
     177                'success'  => false,
     178                'startdate' => $startdate,
     179                'enddate' => $enddate,
     180                'wpdb_error' => $wpdb->last_error,
     181            ];
     182
     183            return new \WP_REST_Response($response_data, 200);
     184        }
     185
     186        $transaction_agent = new Transaction_Manager();
     187        $count = 0;
     188        if (!empty($results)) {
     189            foreach ($results as $nftTransactionObj) {
     190                $reprocessCount = Database::get_nf_data($nftTransactionObj['order_id'],Constants::TRANSACTION_STATUS_REPROCESS_COUNT_KEY, false);
     191                if (!empty($reprocessCount)) {
     192                    $reprocessCount = $reprocessCount + 1;
     193                }
     194                else {
     195                    $reprocessCount = 1;
     196                }
     197
     198                if ($reprocessCount < 3) {
     199                    Database::update_nf_data($nftTransactionObj['order_id'],Constants::TRANSACTION_STATUS_KEY, Constants::TRANSACTION_STATUS_REPROCESS);
     200                    Database::update_nf_data($nftTransactionObj['order_id'],Constants::TRANSACTION_STATUS_REPROCESS_COUNT_KEY, $reprocessCount);
     201                    $transaction_agent->evaluate_transaction($nftTransactionObj['order_id'], [
     202                        'TRANSACTION_REVIEW_REFRESH_LIMIT' => (Transaction_Manager::TRANSACTION_REVIEW_REFRESH_LIMIT*4)
     203                    ]);
     204                    Database::update_nf_data($nftTransactionObj['order_id'],Constants::TRANSACTION_STATUS_KEY, Constants::TRANSACTION_STATUS_REPROCESS_COMPLETE);
     205                    $count++;
     206                }
     207            }
     208        }
     209
     210        $response_data = [
     211            'message'  => 'Reprocessing run finished successfully.',
     212            'success'  => true,
     213            'startdate' => $startdate,
     214            'enddate' => $enddate,
     215            'count' => $count,
     216        ];
     217
     218        return new \WP_REST_Response($response_data, 200);
     219    }
     220
     221    /**
     222     * Callback function to fetch how many transactions are eligible for reprocessing
     223     *
     224     * @param WP_REST_Request $request The REST request.
     225     * @return WP_REST_Response The response.
     226     */
     227    public static function reprocess_transactions_count($request) {
     228        global $wpdb;
     229
     230        $startdate = $request->get_param('startdate') . ' 00:00:00';
     231        $enddate = $request->get_param('enddate') . ' 23:59:59';
     232
     233        // fetch count of all orders placed in this range that are eligible for reprocessing
     234        $nfTransactionsTable = $wpdb->prefix . "nf_transactions";
     235        $wcOrdersTable = $wpdb->prefix . "wc_orders";
     236        $sql = $wpdb->prepare("
     237            SELECT
     238                count(distinct(nft.order_id)) as totalCount
     239            FROM
     240                {$wcOrdersTable} wco
     241            INNER JOIN
     242                {$nfTransactionsTable} nft
     243            ON
     244                (
     245                    nft.meta_value = 'reprocess'
     246                    OR
     247                    nft.meta_value = 'gatewaydisabled'
     248                )
     249                AND           
     250                nft.meta_key = '_nofraud_transaction_review_status'
     251                AND
     252                nft.order_id = wco.id   
     253            WHERE
     254                wco.date_created_gmt <= %s 
     255                AND
     256                wco.date_created_gmt >= %s
     257                AND
     258                wco.status NOT IN ('wc-completed', 'wc-cancelled', 'wc-refunded', 'wc-failed')
     259                AND
     260                wco.type = 'shop_order'
     261        ", $enddate, $startdate);
     262        if ('yes' !== get_option('woocommerce_custom_orders_table_enabled')) {
     263            $wcPostsTable = $wpdb->prefix . "posts";
     264            $sql = $wpdb->prepare("
     265            SELECT
     266                count(distinct(nft.order_id)) as totalCount
     267            FROM
     268                {$wcPostsTable} wpt
     269            INNER JOIN
     270                {$nfTransactionsTable} nft
     271            ON
     272                (
     273                    nft.meta_value = 'reprocess'
     274                    OR
     275                    nft.meta_value = 'gatewaydisabled'
     276                )
     277                AND           
     278                nft.meta_key = '_nofraud_transaction_review_status'
     279                AND
     280                nft.order_id = wpt.id   
     281            WHERE
     282                wpt.post_date_gmt <= %s 
     283                AND
     284                wpt.post_date_gmt >= %s
     285                AND
     286                wpt.post_status NOT IN ('wc-completed', 'wc-cancelled', 'wc-refunded', 'wc-failed')
     287                AND
     288                wpt.post_type = 'shop_order'
     289        ", $enddate, $startdate);
     290        }
     291
     292        $results = $wpdb->get_results($sql, ARRAY_A);
     293
     294        $count = 0;
     295        if ($results === null) {
     296            $response_data = [
     297                'message'  => 'Reprocess eligible count failed',
     298                'success'  => false,
     299                'startdate' => $startdate,
     300                'enddate' => $enddate,
     301                'wpdb_error' => $wpdb->last_error,
     302            ];
     303
     304            return new \WP_REST_Response($response_data, 200);
     305        }
     306
     307        $sampleData = [];
     308        if (!empty($results)) {
     309            $count = $results[0]['totalCount'];
     310
     311            $sql = $wpdb->prepare("
     312                SELECT
     313                    wco.id as order_id, wco.type, wco.date_created_gmt, wco.status, nft.meta_key, nft.meta_value
     314                FROM
     315                    {$wcOrdersTable} wco
     316                INNER JOIN
     317                    {$nfTransactionsTable} nft
     318                ON
     319                    (
     320                        nft.meta_value = 'reprocess'
     321                        OR
     322                        nft.meta_value = 'gatewaydisabled'
     323                    )
     324                    AND           
     325                    nft.meta_key = '_nofraud_transaction_review_status'
     326                    AND
     327                    nft.order_id = wco.id   
     328                WHERE
     329                    wco.date_created_gmt <= %s 
     330                    AND
     331                    wco.date_created_gmt >= %s
     332                    AND
     333                    wco.status NOT IN ('wc-completed', 'wc-cancelled', 'wc-refunded', 'wc-failed')
     334                    AND
     335                    wco.type = 'shop_order'
     336                LIMIT 3
     337            ", $enddate, $startdate);
     338            if ('yes' !== get_option('woocommerce_custom_orders_table_enabled')) {
     339                $wcPostsTable = $wpdb->prefix . "posts";
     340                $sql = $wpdb->prepare("
     341                SELECT
     342                    wpt.id as order_id, wpt.post_type, wpt.post_date_gmt, wpt.post_status, nft.meta_key, nft.meta_value
     343                FROM
     344                    {$wcPostsTable} wpt
     345                INNER JOIN
     346                    {$nfTransactionsTable} nft
     347                ON
     348                    (
     349                        nft.meta_value = 'reprocess'
     350                        OR
     351                        nft.meta_value = 'gatewaydisabled'
     352                    )
     353                    AND           
     354                    nft.meta_key = '_nofraud_transaction_review_status'
     355                    AND
     356                    nft.order_id = wpt.id   
     357                WHERE
     358                    wpt.post_date_gmt <= %s 
     359                    AND
     360                    wpt.post_date_gmt >= %s
     361                    AND
     362                    wpt.post_status NOT IN ('wc-completed', 'wc-cancelled', 'wc-refunded', 'wc-failed')
     363                    AND
     364                    wpt.post_type = 'shop_order'
     365                LIMIT 3
     366            ", $enddate, $startdate);
     367            }
     368            $sampleData = $wpdb->get_results($sql, ARRAY_A);
     369        }
     370
     371        $response_data = [
     372            'message'  => 'Reprocess eligible count succeeded. Note that just because an order is eligible does not mean it will be reprocessed',
     373            'success'  => true,
     374            'startdate' => $startdate,
     375            'enddate' => $enddate,
     376            'count' => $count,
     377            'sample' => $sampleData,
     378        ];
     379
     380        return new \WP_REST_Response($response_data, 200);
     381    }
     382
     383    /**
     384     * Callback function to fetch reprocess completion data
     385     *
     386     * @param WP_REST_Request $request The REST request.
     387     * @return WP_REST_Response The response.
     388     */
     389    public static function reprocess_transactions_count_completed($request) {
     390        global $wpdb;
     391
     392        $startdate = $request->get_param('startdate') . ' 00:00:00';
     393        $enddate = $request->get_param('enddate') . ' 23:59:59';
     394
     395        // fetch count of all orders placed in this range that are eligible for reprocessing
     396        $nfTransactionsTable = $wpdb->prefix . "nf_transactions";
     397        $wcOrdersTable = $wpdb->prefix . "wc_orders";
     398        $sql = $wpdb->prepare("
     399            SELECT
     400                nft.meta_value, count(distinct(nft.order_id)) as totalCount
     401            FROM   
     402                {$nfTransactionsTable} nft
     403            WHERE
     404                (
     405                    nft.meta_value = 'reprocess'
     406                    OR
     407                    nft.meta_value = 'reprocesscomplete'
     408                )
     409                AND           
     410                nft.meta_key = '_nofraud_transaction_review_status'
     411            GROUP BY
     412                nft.meta_value   
     413        ", $enddate, $startdate);
     414        $results = $wpdb->get_results($sql, ARRAY_A);
     415
     416        $count = 0;
     417        if ($results === null) {
     418            $response_data = [
     419                'message'  => 'Reprocess totals count failed',
     420                'success'  => false,
     421                'wpdb_error' => $wpdb->last_error,
     422            ];
     423
     424            return new \WP_REST_Response($response_data, 200);
     425        }
     426        $completed_count = 0;
     427        $reprocessing_count = 0;
     428        if (!empty($results)) {
     429            foreach ($results as $resultObj) {
     430                if ($resultObj['meta_value'] == 'reprocess') {
     431                    $reprocessing_count = $resultObj['totalCount'];
     432                }
     433                if ($resultObj['meta_value'] == 'reprocesscomplete') {
     434                    $completed_count = $resultObj['totalCount'];
     435                }
     436            }
     437        }
     438
     439        $response_data = [
     440            'message'  => 'Reprocess completed count succeeded.',
     441            'success'  => true,
     442            'completed_count' => $completed_count,
     443            'reprocessing_count' => $reprocessing_count,
     444        ];
     445
     446        return new \WP_REST_Response($response_data, 200);
    33447    }
    34448
     
    366780
    367781    /**
    368      * Add NoFraud metadata to
     782     * Add NoFraud metadata to woocommerce_rest_prepare_shop_order_object
    369783     *
    370784     * @since 4.5.0
  • nofraud-protection/trunk/changelog.txt

    r3207152 r3216172  
    11*** NoFraud Protection for WooCommerce Changelog ***
     2
     32025-01-02 - version 4.5.5
     4* Feature - Added REST API setting and API Route for reprocessing unprocessed orders
     5* Feature - Added choice for SkyVerge Authorize.net Autovoid feature to choose between WooCommerce method and legacy method
    26
    372024-12-10 - version 4.5.4
  • nofraud-protection/trunk/common/class-database.php

    r3207152 r3216172  
    3333            }
    3434        }
    35 
    3635
    3736        $tablename = $wpdb->prefix . "nf_transactions";
  • nofraud-protection/trunk/common/class-environment.php

    r3207152 r3216172  
    2121     * @var string Plugin version.
    2222     */
    23     const PLUGIN_VERSION = '4.5.4';
     23    const PLUGIN_VERSION = '4.5.5';
    2424
    2525    /**
  • nofraud-protection/trunk/composer.json

    r3207152 r3216172  
    11{
    22    "name": "nofraud/nofraud-protection",
    3     "version": "4.5.4",
     3    "version": "4.5.5",
    44    "description": "NoFraud fraud detection service plugin for WooCommerce",
    55    "type": "wordpress-plugin",
  • nofraud-protection/trunk/nofraud-protection.php

    r3207152 r3216172  
    44 * Plugin URI: https://nofraud.com
    55 * Description: Eliminate fraudulent orders on your WooCommerce store with NoFraud. If you get a fraud chargeback, NoFraud will pay you back! Visit www.nofraud.com to learn more.
    6  * Version: 4.5.4
     6 * Version: 4.5.5
    77 * Author: NoFraud
    88 * Requires PHP: 5.6
  • nofraud-protection/trunk/pages/class-woocommerce-settings.php

    r3207152 r3216172  
    3030        // Update by NoFraud setting tab.
    3131        add_action('woocommerce_update_options_nofraud', [$instance, 'update_settings_tab'], 10);
     32        // Load scripts
     33        add_action('admin_enqueue_scripts', [$instance, 'enqueue_nofraud_settings_script']);
     34
    3235    }
    3336
     
    3942    public function admin_init() {
    4043        global $wpdb;
     44
     45        wp_register_script( 'nofraud-protection-settings-script', plugins_url('../assets/js/settings.js', __FILE__) );
    4146
    4247        $current_version_in_db = get_option('woocommerce_nofraud_protection_version', false);
     
    178183        }
    179184        $updated_order_statuses['donothing'] = 'Do Nothing';
     185
     186        $voidrefund_modes  = [
     187            'WOOCOMMERCE' => 'WooCommerce Refund',
     188            'GATEWAY' => 'Legacy Direct Gateway',
     189        ];
    180190
    181191        $transaction_types = [
     
    236246            ],
    237247            [
     248                'title' => __('Void/Refund Mode', 'nofraud-protection'),
     249                'type' => 'select',
     250                'class' => 'wc-enhanced-select',
     251                'desc' => __('WooCommerce Refund will create a refund via WooCommerce methods, Legacy Direct Gateway will only submit an API request to the payment gateway', 'nofraud-protection'),
     252                'options' => $voidrefund_modes,
     253                'id' => 'woocommerce_nofraud_automatic_voidrefund_mode',
     254                'default' => "WOOCOMMERCE",
     255            ],
     256            [
    238257                'title' => __('Transaction Status to Initiate Decision Evaluation on', 'nofraud-protection'),
    239258                'type' => 'select',
     
    458477                'default' => 'yes',
    459478            ];
    460        
     479
     480        $settings[] =
     481            [
     482                'name' => __('Enable NoFraud REST API', 'nofraud-protection-section-payments'),
     483                'type' => 'checkbox',
     484                'desc' => __('If checked, NoFraud API endpoints will be enabled. This is disabled by default.', 'nofraud-protection-section-payments'),
     485                'id' => 'woocommerce_nofraud_enable_rest_api',
     486                'default' => 'no',
     487            ];
     488
    461489        $settings[] =
    462490            [
     
    467495        return apply_filters('woocommerce_nofraud_get_settings', $settings);
    468496    }
     497
     498    public function enqueue_nofraud_settings_script($hook) {
     499        // Only load on WooCommerce settings page
     500        if ($hook === 'woocommerce_page_wc-settings') {
     501            wp_enqueue_script(
     502                'nofraud-protection-settings-script',
     503                plugins_url('../assets/js/settings.js', __FILE__),
     504                array(),
     505                '1.0',
     506                true
     507            );
     508        }
     509    }
    469510}
    470511
  • nofraud-protection/trunk/payment/methods/class-nofraud-authorize-net-cim-credit-card.php

    r3192579 r3216172  
    179179        $order_id = $order->get_id();
    180180
    181         $refund_amount = $order->get_remaining_refund_amount();
    182         $calculated_refund_amount = 0;
    183 
    184         $order_items = $order->get_items();
    185         $line_items = array();
    186 
    187         if (!empty($order_items)) {
    188             foreach($order_items as $item_id => $item) {
    189                 $item_meta  = $order->get_item_meta( $item_id );
    190                 $tax_data = $item_meta['_line_tax_data'];
    191                 $refund_tax = 0;
    192                 if(!empty($tax_data[0]) && is_array($tax_data[0])) {
    193                     $refund_tax = array_map('wc_format_decimal', $tax_data[0]);
    194                 }
    195                 $calculated_refund_amount = wc_format_decimal($calculated_refund_amount) + wc_format_decimal($item_meta['_line_total'][0]);
    196                 $line_items[$item_id] = [
    197                     'qty' => $item_meta['_qty'][0],
    198                     'refund_total' => wc_format_decimal($item_meta['_line_total'][0]),
    199                     'refund_tax' =>  $refund_tax,
    200                 ];
    201             }
    202         }
    203 
    204         $refund = wc_create_refund(array(
    205             'amount' => $refund_amount,
    206             'reason' => 'NoFraud automatically voided/refunded the charge for this order due to FAIL decision',
    207             'order_id' => $order_id,
    208             'refund_payment' => true,
    209             'restock_items' => true,
    210             'line_items' => $line_items,
    211         ));
    212         if (is_wp_error($refund)) {
    213             $order_note = sprintf(__('NoFraud attempted to automatically void/refund the charge for this order but failed due to error: %s', 'nofraud-protection'), $refund->get_error_message());
    214             wc_create_order_note($order_id, $order_note);
    215         } else {
    216             $order->update_meta_data( 'nofraud_voidrefund_processed', 1 );
    217 
    218             $order_note = sprintf(__('NoFraud automatically voided/refunded the charge for this order (Transaction ID: %s)', 'nofraud-protection'), $transaction_id);
    219             wc_create_order_note($order_id, $order_note);
     181        // determine which mode to use to process this voidrefund
     182        $woocommerce_nofraud_automatic_voidrefund_mode = get_option('woocommerce_nofraud_automatic_voidrefund_mode', 'WOOCOMMERCE');
     183
     184        if ($woocommerce_nofraud_automatic_voidrefund_mode == 'GATEWAY') {
     185            // Legacy Payment Gateway Mode
     186            //retrieve transaction details by transaction ID
     187            $request = new AnetAPI\GetTransactionDetailsRequest();
     188            $request->setMerchantAuthentication($this->merchantAuthentication);
     189            $request->setTransId($transaction_id);
     190
     191            $controller = new AnetController\GetTransactionDetailsController($request);
     192
     193            $response = null;
     194            if('test' === $this->woocommerce_authorize_net_cim_credit_card_settings['environment']) {
     195                $response = $controller->executeWithApiResponse( \net\authorize\api\constants\ANetEnvironment::SANDBOX);
     196            }
     197            else {
     198                $response = $controller->executeWithApiResponse( \net\authorize\api\constants\ANetEnvironment::PRODUCTION);
     199            }
     200
     201            $last4 = null;
     202            $amountToRefund = '0.00';
     203            $transactionStatus = null;
     204            if ((null !== $response) && (self::AUTHORIZENET_RESPONSE_CODES['RESPONSE_OK'] === $response->getMessages()->getResultCode()))
     205            {
     206                $transactionDetailsObj = $response->getTransaction();
     207
     208                $creditCardMaskedTypeObj = $transactionDetailsObj->getPayment()->getCreditCard();
     209                if (!empty($creditCardMaskedTypeObj) && is_object($creditCardMaskedTypeObj) && method_exists($creditCardMaskedTypeObj,'getCardType')) {
     210                    if(!empty($creditCardMaskedTypeObj->getCardNumber())) {
     211                        $apiLast4CardNumber = substr($creditCardMaskedTypeObj->getCardNumber(),-4);
     212                        if(ctype_digit($apiLast4CardNumber) && 4 === strlen($apiLast4CardNumber)) {
     213                            $last4 = sanitize_text_field($apiLast4CardNumber);
     214                        }
     215                    }
     216                }
     217
     218                $amountToRefund = $transactionDetailsObj->getSettleAmount();
     219                $transactionStatus = $transactionDetailsObj->getTransactionStatus();
     220            }
     221            else
     222            {
     223                $errorMessages = $response->getMessages()->getMessage();
     224                error_log('NoFraud error: NoFraud_Authorize_Net_Cim_Credit_Card refund(): ' . print_r($errorMessages, true) );
     225            }
     226
     227            if (in_array($transactionStatus, ['capturedPendingSettlement','authorizedPendingCapture'])) {
     228                $tresponse = $nofraud_payment_method->void($_wc_authorize_net_cim_credit_card_trans_id);
     229                if ($tresponse != null && $tresponse->getMessages() != null) {
     230                    Debug::add_debug_message([
     231                        'function' => 'woocommerce_nofraud_automatic_voidrefund:VOID:success',
     232                        'order_id' => $order_id,
     233                        '_wc_authorize_net_cim_credit_card_void_auth_code' => $tresponse->getAuthCode(),
     234                        '_wc_authorize_net_cim_credit_card_void_trans_id' => $tresponse->getTransId(),
     235                    ]);
     236
     237                    $order->update_meta_data( '_wc_authorize_net_cim_credit_card_void_auth_code', $tresponse->getAuthCode() );
     238                    $order->update_meta_data( '_wc_authorize_net_cim_credit_card_void_trans_id', $tresponse->getTransId() );
     239                    $order->update_meta_data( 'nofraud_voidrefund_processed', 1 );
     240
     241                    $order_note = sprintf(__('NoFraud automatically voided the charge for this order (Voided Transaction ID: %s).', 'nofraud-protection'), $_wc_authorize_net_cim_credit_card_trans_id);
     242                    wc_create_order_note($order_id, $order_note);
     243                }
     244                else {
     245                    if ($tresponse->getErrors() != null) {
     246                        Debug::add_debug_message([
     247                            'function' => 'woocommerce_nofraud_automatic_voidrefund:VOID:failed',
     248                            'order_id' => $order_id,
     249                            'error_code' => $tresponse->getErrors()[0]->getErrorCode(),
     250                            'error_msg' => $tresponse->getErrors()[0]->getErrorText(),
     251                        ]);
     252
     253                        $order_note = sprintf(__('NoFraud attempted to void the charge for this order but the attempt failed with error code (%1$s):  %2$s.', 'nofraud-protection'), $tresponse->getErrors()[0]->getErrorCode(), $tresponse->getErrors()[0]->getErrorText());
     254                        wc_create_order_note($order_id, $order_note);
     255                    }
     256                }
     257
     258                if ('settledSuccessfully' === $transactionStatus) {
     259                    $_wc_authorize_net_cim_credit_card_account_four = $order->get_meta('_wc_authorize_net_cim_credit_card_account_four');
     260                    if (!empty($_wc_authorize_net_cim_credit_card_account_four)) {
     261                        $tresponse = $nofraud_payment_method->refund($order, $_wc_authorize_net_cim_credit_card_trans_id, $last4, $amountToRefund);
     262                        if ($tresponse != null && $tresponse->getMessages() != null) {
     263                            Debug::add_debug_message([
     264                                'function' => 'woocommerce_nofraud_automatic_voidrefund:REFUND:success',
     265                                'order_id' => $order_id,
     266                                '_wc_authorize_net_cim_credit_card_void_auth_code' => $tresponse->getAuthCode(),
     267                                '_wc_authorize_net_cim_credit_card_void_trans_id' => $tresponse->getTransId(),
     268                            ]);
     269
     270                            $order->update_meta_data( '_wc_authorize_net_cim_credit_card_refund_auth_code', $tresponse->getAuthCode() );
     271                            $order->update_meta_data( '_wc_authorize_net_cim_credit_card_refund_trans_id', $tresponse->getTransId() );
     272                            $order->update_meta_data( 'nofraud_voidrefund_processed', 1 );
     273
     274                            $order_note = sprintf(__('NoFraud automatically refunded the charge for this order (Transaction ID %1$s)', 'nofraud-protection'), $tresponse->getTransId());
     275                            wc_create_order_note($order_id, $order_note);
     276                        }
     277                        else {
     278                            if ($tresponse->getErrors() != null) {
     279                                Debug::add_debug_message([
     280                                    'function' => 'woocommerce_nofraud_automatic_voidrefund:REFUND:failed',
     281                                    'order_id' => $order_id,
     282                                    'error_code' => $tresponse->getErrors()[0]->getErrorCode(),
     283                                    'error_msg' => $tresponse->getErrors()[0]->getErrorText(),
     284                                ]);
     285
     286                                $order_note = sprintf(__('NoFraud attempted to refund the charge for this order but the attempt failed with error code (%1$s):  %2$s.', 'nofraud-protection'), $tresponse->getErrors()[0]->getErrorCode(), $tresponse->getErrors()[0]->getErrorText());
     287                                wc_create_order_note($order_id, $order_note);
     288                            }
     289                        }
     290                    }
     291                    else {
     292                        Debug::add_debug_message([
     293                            'function' => 'woocommerce_nofraud_automatic_voidrefund:REFUND:failed:missing_last4',
     294                            'order_id' => $order_id,
     295                        ]);
     296                    }
     297                }
     298            }
     299        }
     300        else {
     301            // WooCommerce Refund Mode
     302            $refund_amount = $order->get_remaining_refund_amount();
     303            $calculated_refund_amount = 0;
     304
     305            $order_items = $order->get_items();
     306            $line_items = array();
     307
     308            if (!empty($order_items)) {
     309                foreach($order_items as $item_id => $item) {
     310                    $item_meta  = $order->get_item_meta( $item_id );
     311                    $tax_data = $item_meta['_line_tax_data'];
     312                    $refund_tax = 0;
     313                    if(!empty($tax_data[0]) && is_array($tax_data[0])) {
     314                        $refund_tax = array_map('wc_format_decimal', $tax_data[0]);
     315                    }
     316                    $calculated_refund_amount = wc_format_decimal($calculated_refund_amount) + wc_format_decimal($item_meta['_line_total'][0]);
     317                    $line_items[$item_id] = [
     318                        'qty' => $item_meta['_qty'][0],
     319                        'refund_total' => wc_format_decimal($item_meta['_line_total'][0]),
     320                        'refund_tax' =>  $refund_tax,
     321                    ];
     322                }
     323            }
     324
     325            $refund = wc_create_refund(array(
     326                'amount' => $refund_amount,
     327                'reason' => 'NoFraud automatically voided/refunded the charge for this order due to FAIL decision',
     328                'order_id' => $order_id,
     329                'refund_payment' => true,
     330                'restock_items' => true,
     331                'line_items' => $line_items,
     332            ));
     333            if (is_wp_error($refund)) {
     334                $order_note = sprintf(__('NoFraud attempted to automatically void/refund the charge for this order but failed due to error: %s', 'nofraud-protection'), $refund->get_error_message());
     335                wc_create_order_note($order_id, $order_note);
     336            } else {
     337                $order->update_meta_data( 'nofraud_voidrefund_processed', 1 );
     338
     339                $order_note = sprintf(__('NoFraud automatically voided/refunded the charge for this order (Transaction ID: %s)', 'nofraud-protection'), $transaction_id);
     340                wc_create_order_note($order_id, $order_note);
     341            }
    220342        }
    221343    }
  • nofraud-protection/trunk/payment/transactions/class-constants.php

    r2974562 r3216172  
    5757     */
    5858    const TRANSACTION_STATUS_GATEWAYDISABLED = 'gatewaydisabled';
    59    
     59
     60    /**
     61     * "Transaction Reprocess Status"
     62     *
     63     * @var string Reprocess means the order was triggered for reprocessing
     64     */
     65    const TRANSACTION_STATUS_REPROCESS = 'reprocess';
     66
     67    /**
     68     * "Transaction Reprocess Count"
     69     *
     70     * @var string Reprocesscount
     71     */
     72    const TRANSACTION_STATUS_REPROCESS_COUNT_KEY = 'reprocesscount';
     73
     74    /**
     75     * "Transaction Reprocess Completed Status"
     76     *
     77     * @var string Reprocesscomplete means the order completed reprocessing
     78     */
     79    const TRANSACTION_STATUS_REPROCESS_COMPLETE = 'reprocesscomplete';
     80
    6081    /**
    6182     * Response from do_action of external plugin
  • nofraud-protection/trunk/payment/transactions/class-transaction-manager.php

    r3192579 r3216172  
    313313     *
    314314     * @param int $order_id Order ID.
    315      * @return stdObject NoFraud transaction review.
     315     * @param array $options Additional options
     316     * @return stdObject NoFraud transaction review.
    316317     *
    317318     * @since 2.0.0
    318319     */
    319     public function evaluate_transaction( $order_id ) {
     320    public function evaluate_transaction( $order_id, $options = [] ) {
    320321        Debug::add_debug_message([
    321322            'function' => 'NoFraud:Transaction_Manager:evaluate_transaction',
     
    326327        $original_transaction_review = Database::get_nf_data($order_id, Constants::TRANSACTION_REVIEW_KEY);
    327328
    328         $transaction_review = $this->get_transaction_review($order_id);
     329        $transaction_review = $this->get_transaction_review($order_id, $options);
    329330        if (!empty($transaction_review)) {
    330331            if (isset($transaction_review->id)) {
     
    565566     * Get transaction review.
    566567     *
    567      * @param int $order_id Order ID.
     568     * @param int $order_id Order ID
     569     * @param array $options Additional options
    568570     * @return stdObject|false NoFraud transaction review.
    569571     */
    570     public function get_transaction_review( $order_id ) {
     572    public function get_transaction_review( $order_id, $options = [] ) {
    571573        Debug::add_debug_message([
    572574            'function' => 'NoFraud:Transaction_Manager:get_transaction_review()',
     
    634636
    635637        // sanity check don't do a decision if order is older than TRANSACTION_REVIEW_REFRESH_LIMIT
    636         if (strtotime($order->get_date_created()) < time() - self::TRANSACTION_REVIEW_REFRESH_LIMIT) {
     638        $maxDatetimeRefreshable = time() - self::TRANSACTION_REVIEW_REFRESH_LIMIT;
     639
     640        // exception: if TRANSACTION_REVIEW_REFRESH_LIMIT is defined in options, overwrite
     641        if (!empty($options['TRANSACTION_REVIEW_REFRESH_LIMIT'])) {
     642            Debug::add_debug_message([
     643                'function' => 'NoFraud:Transaction_Manager:get_transaction_review():custom_refresh_limit',
     644                'order_id' => $order_id,
     645                'TRANSACTION_REVIEW_REFRESH_LIMIT' => $options['TRANSACTION_REVIEW_REFRESH_LIMIT'],
     646            ]);
     647            $maxDatetimeRefreshable = time() - $options['TRANSACTION_REVIEW_REFRESH_LIMIT'];
     648        }
     649
     650        if (strtotime($order->get_date_created()) < $maxDatetimeRefreshable) {
    637651            Debug::add_debug_message([
    638652                'function' => 'NoFraud:Transaction_Manager:get_transaction_review():order_too_old',
     
    646660
    647661        // Otherwise, create a new transaction review.
    648         return $this->create_transaction_review($order_id);
     662        return $this->create_transaction_review($order_id, $options);
    649663    }
    650664
     
    679693     * Submit transaction data to NoFraud API to create a transaction review.
    680694     *
    681      * @param int $order_id Order ID.
    682      * @return stdObject|false NoFraud transaction review.
     695     * @param int $order_id Order ID
     696     * @param array $options Additional options
     697     * @return stdObject|false NoFraud transaction review.
    683698     */
    684     private function create_transaction_review( $order_id ) {
     699    private function create_transaction_review( $order_id, $options = [] ) {
    685700        Debug::add_debug_message([
    686701            'function' => 'create_transaction_review',
     
    692707
    693708        // sanity check don't do a decision if order is older than TRANSACTION_REVIEW_REFRESH_LIMIT
    694         if (strtotime($order->get_date_created()) < time() - self::TRANSACTION_REVIEW_REFRESH_LIMIT) {
     709        $maxDatetimeRefreshable = time() - self::TRANSACTION_REVIEW_REFRESH_LIMIT;
     710
     711        // exception: if TRANSACTION_REVIEW_REFRESH_LIMIT is defined in options, overwrite
     712        if (!empty($options['TRANSACTION_REVIEW_REFRESH_LIMIT'])) {
     713            Debug::add_debug_message([
     714                'function' => 'NoFraud:Transaction_Manager:create_transaction_review():custom_refresh_limit',
     715                'order_id' => $order_id,
     716                'TRANSACTION_REVIEW_REFRESH_LIMIT' => $options['TRANSACTION_REVIEW_REFRESH_LIMIT'],
     717            ]);
     718            $maxDatetimeRefreshable = time() - $options['TRANSACTION_REVIEW_REFRESH_LIMIT'];
     719        }
     720
     721        if (strtotime($order->get_date_created()) < $maxDatetimeRefreshable) {
    695722            Debug::add_debug_message([
    696723                'function' => 'create_transaction_review:order_too_old',
  • nofraud-protection/trunk/readme.txt

    r3207152 r3216172  
    55Requires PHP: 5.6
    66Tested up to: 6.7.1
    7 Stable tag: 4.5.4
     7Stable tag: 4.5.5
    88License: GPL-3.0
    99License URI: http://www.gnu.org/licenses/gpl-3.0.txt
Note: See TracChangeset for help on using the changeset viewer.