Plugin Directory

Changeset 3490786


Ignore:
Timestamp:
03/25/2026 11:01:09 AM (4 days ago)
Author:
peachpay
Message:

1.120.23

Location:
peachpay-for-woocommerce
Files:
893 added
16 edited

Legend:

Unmodified
Added
Removed
  • peachpay-for-woocommerce/trunk/changelog.txt

    r3486614 r3490786  
    11*** PeachPay for WooCommerce Changelog ***
     2
     32026-03-25 - version 1.120.23
     4* **Fixed**:
     5  * **Subscriptions**: Prevented duplicate subscription renewal charges across ConvesioPay and Stripe.
     6  * **Stripe**: Fixed duplicate WooCommerce refunds triggered by Stripe charge.refunded webhook.
     7* **Improved**:
     8  * **Logging**: Standardized payment logging between ConvesioPay and Stripe for better consistency and debugging.
     9  * **NMI**: Improved homepage payment box with UI reorganization and enhanced validation.
     10* **Build**:
     11  * Suppressed known CSS browser-support stylelint warnings to reduce noise in builds.
    212
    3132026-03-19 - version 1.120.22
  • peachpay-for-woocommerce/trunk/core/modules/dashboard/settings-homepage.php

    r3486472 r3490786  
    116116            'heap_id'     => 'nmi',
    117117            'hash'        => '#nmi',
    118             'main_logo'   => PeachPay::get_asset_url( '/img/marks/convesiopay1.svg' ),
     118            'main_logo'   => PeachPay::get_asset_url( '/img/marks/nmi/nmi.png' ),
    119119            'connection'  => (bool) peachpay_nmi_is_enabled(),
    120             'description' => 'The all-in-one payment solution to maximize revenue and streamline the payment process. Make test payments following these instructions.',
    121             'featured'    => true, // Make ConvesioPay a featured card (double width)
     120            'description' => 'NMI is a great fit for online merchants who want a flexible gateway with broad integration options and risk controls.',
     121            'featured'    => false,
    122122            'sub_logos'   => array(
    123                 PeachPay::get_asset_url( '/img/marks/convesiopay/visa.svg' ),
    124                 PeachPay::get_asset_url( '/img/marks/convesiopay/amex.png' ),
    125                 PeachPay::get_asset_url( '/img/marks/convesiopay/Mastercard.png' ),
    126                 PeachPay::get_asset_url( '/img/marks/convesiopay/Apple_Pay.png' ),
    127                 PeachPay::get_asset_url( '/img/marks/convesiopay/Google_Pay.png' ),
    128                 PeachPay::get_asset_url( '/img/marks/convesiopay/bitcoin.png' ),
    129                 PeachPay::get_asset_url( '/img/marks/convesiopay/maestro.png' ),
    130                 PeachPay::get_asset_url( '/img/marks/convesiopay/discover-network.png' ),
    131                 PeachPay::get_asset_url( '/img/marks/convesiopay/UnionPay.png' )
     123                PeachPay::get_asset_url( '/img/marks/cards.svg' ),
     124                PeachPay::get_asset_url( '/img/marks/applepay-full.svg' ),
    132125            ),
    133126        ),
  • peachpay-for-woocommerce/trunk/core/payments/convesiopay/admin/class-peachpay-convesiopay-fetch-payment-status-manually.php

    r3460037 r3490786  
    185185            $body = wp_remote_retrieve_body( $response );
    186186            if ( $code !== 200 ) {
    187                 if ( function_exists( 'peachpay_log' ) ) {
    188                     peachpay_log( 'error', 'PeachPay Fetch Status: GET payment HTTP ' . $code . ' for payment ' . $payment_id . ' - ' . substr( $body, 0, 500 ) );
     187                if (function_exists('peachpay_log')) {
     188                    peachpay_log(
     189                        'error',
     190                        'Failed to fetch payment status from ConvesioPay Api',
     191                        array(
     192                            'event'     => 'payments.convesiopay_admin.payment.fetch.failed',
     193                            'component' => 'payments',
     194                            'feature'   => 'convesiopay_admin',
     195                            'operation' => 'payment.fetch',
     196                            'outcome'   => 'failed',
     197                            'method'    => __METHOD__,
     198                            'line'      => __LINE__,
     199                            'data'      => array(
     200                                'details' => '',
     201                                'response_code' => $code,
     202                                'response_body' => json_decode($body, true),
     203                                'payment_id' => $payment_id,
     204                            )
     205                        )
     206                    );
    189207                }
    190208                return false;
     
    193211            $data = json_decode( $body, true );
    194212            if ( ! is_array( $data ) || empty( $data['status'] ) ) {
    195                 if ( function_exists( 'peachpay_log' ) ) {
    196                     peachpay_log( 'error', 'PeachPay Fetch Status: GET payment invalid response for ' . $payment_id . ' - missing status or invalid JSON' );
     213                if (function_exists('peachpay_log')) {
     214                    peachpay_log(
     215                        'error',
     216                        'Failed to fetch payment status from ConvesioPay Api',
     217                        array(
     218                            'event'     => 'payments.convesiopay_admin.payment.fetch.failed',
     219                            'component' => 'payments',
     220                            'feature'   => 'convesiopay_admin',
     221                            'operation' => 'payment.fetch',
     222                            'outcome'   => 'failed',
     223                            'method'    => __METHOD__,
     224                            'line'      => __LINE__,
     225                            'data'      => array(
     226                                'details' => 'The response is not a valid JSON or missing status',
     227                                'response_body' => json_decode($body, true),
     228                                'payment_id' => $payment_id,
     229                            )
     230                        )
     231                    );
    197232                }
    198233                return false;
  • peachpay-for-woocommerce/trunk/core/payments/convesiopay/admin/class-peachpay-convesiopay-manual-capture.php

    r3460037 r3490786  
    186186            ) );
    187187        } else {
    188             peachpay_log( 'error', 'ConvesioPay: Manual capture failed - ' . $result['message'] . ' (order ' . $order_id . ', payment ' . $payment_id . ')' );
    189188            $order->add_order_note( sprintf(
    190189                'ConvesioPay capture failed: %s',
     
    263262            ) );
    264263        } else {
    265             peachpay_log( 'error', 'ConvesioPay: Manual cancel failed - ' . $result['message'] . ' (order ' . $order_id . ', payment ' . $payment_id . ')' );
    266264            $order->add_order_note( sprintf(
    267265                'ConvesioPay cancel failed: %s',
     
    302300           
    303301           
    304             peachpay_log( 'debug', 'ConvesioPay: Manual capture API request for payment ' . $payment_id . ' (amount: ' . ( $amount / 100 ) . ' ' . $currency . ')' );
     302            peachpay_log(
     303                'debug',
     304                'Payments: ConvesioPay Manual capture debug.',
     305                array(
     306                    'event'     => 'payments.convesiopay_admin.capture.manual.debug',
     307                    'component' => 'payments',
     308                    'feature'   => 'convesiopay_admin',
     309                    'operation' => 'capture.manual',
     310                    'outcome'   => 'debug',
     311                    'method'    => __METHOD__,
     312                    'line'      => __LINE__,
     313                    'data'      => array(
     314                        'details' => 'ConvesioPay: Manual capture API request for payment ' . $payment_id . ' (amount: ' . ( $amount / 100 ) . ' ' . $currency . ')'
     315            )));
    305316
    306317            // Make API request
     
    316327           
    317328            if ( is_wp_error( $response ) ) {
    318                 peachpay_log( 'error', 'ConvesioPay: Manual capture network error - ' . $response->get_error_message() . ' (payment ' . $payment_id . ')' );
     329                peachpay_log(
     330                    'error',
     331                    'Payments: ConvesioPay Manual capture failed.',
     332                    array(
     333                        'event'     => 'payments.convesiopay_admin.capture.manual.failed',
     334                        'component' => 'payments',
     335                        'feature'   => 'convesiopay_admin',
     336                        'operation' => 'capture.manual',
     337                        'outcome'   => 'failed',
     338                        'method'    => __METHOD__,
     339                        'line'      => __LINE__,
     340                        'data'      => array(
     341                            'details' => 'ConvesioPay: Manual capture network error - ' . $response->get_error_message() . ' (payment ' . $payment_id . ')'
     342                )));
    319343                return array( 'success' => false, 'message' => $response->get_error_message() );
    320344            }
     
    326350            if ( $response_code === 200 ) {
    327351                $response_data = json_decode( $response_body, true );
    328                 peachpay_log( 'info', 'ConvesioPay: Manual capture success - payment ' . $payment_id );
     352                peachpay_log(
     353                    'info',
     354                    'Payments: ConvesioPay Manual capture success.',
     355                    array(
     356                        'event'     => 'payments.convesiopay_admin.capture.manual.success',
     357                        'component' => 'payments',
     358                        'feature'   => 'convesiopay_admin',
     359                        'operation' => 'capture.manual',
     360                        'outcome'   => 'success',
     361                        'method'    => __METHOD__,
     362                        'line'      => __LINE__,
     363                        'data'      => array(
     364                            'details' => 'ConvesioPay: Manual capture success - payment ' . $payment_id
     365                )));
    329366                return array( 'success' => true, 'data' => $response_data );
    330367            } else {
    331368                $error_data = json_decode( $response_body, true );
    332369                $error_message = $error_data['message'] ?? "HTTP $response_code error";
    333                 peachpay_log( 'error', 'ConvesioPay: Manual capture API error - ' . $error_message . ' (payment ' . $payment_id . ')' );
     370                peachpay_log(
     371                    'error',
     372                    'Payments: ConvesioPay Manual capture failed.',
     373                    array(
     374                        'event'     => 'payments.convesiopay_admin.capture.manual.failed',
     375                        'component' => 'payments',
     376                        'feature'   => 'convesiopay_admin',
     377                        'operation' => 'capture.manual',
     378                        'outcome'   => 'failed',
     379                        'method'    => __METHOD__,
     380                        'line'      => __LINE__,
     381                        'data'      => array(
     382                            'details' => 'ConvesioPay: Manual capture API error - ' . $error_message . ' (payment ' . $payment_id . ')'
     383                )));
    334384                return array( 'success' => false, 'message' => $error_message );
    335385            }
     
    359409            $api_url = peachpay_is_test_mode() ? 'https://api-qa.convesiopay.com' : 'https://api.convesiopay.com';
    360410            $cancel_url = $api_url . '/v1/payments/' . $payment_id . '/cancel';
    361             peachpay_log( 'debug', 'ConvesioPay: Manual cancel API request for payment ' . $payment_id );
     411            peachpay_log(
     412                'debug',
     413                'Payments: Manual cancel debug.',
     414                array(
     415                    'event'     => 'payments.convesiopay_admin.cancel.manual.debug',
     416                    'component' => 'payments',
     417                    'feature'   => 'convesiopay_admin',
     418                    'operation' => 'cancel.manual',
     419                    'outcome'   => 'debug',
     420                    'method'    => __METHOD__,
     421                    'line'      => __LINE__,
     422                    'data'      => array(
     423                        'details' => 'ConvesioPay: Manual cancel API request for payment ' . $payment_id
     424                )));
    362425
    363426            // Make API request (no body required for cancel)
     
    373436           
    374437            if ( is_wp_error( $response ) ) {
    375                 peachpay_log( 'error', 'ConvesioPay: Manual cancel network error - ' . $response->get_error_message() . ' (payment ' . $payment_id . ')' );
     438                peachpay_log(
     439                'error',
     440                'Payments: ConvesioPay Manual cancel failed.',
     441                array(
     442                    'event'     => 'payments.convesiopay_admin.cancel.manual.failed',
     443                    'component' => 'payments',
     444                    'feature'   => 'convesiopay_admin',
     445                    'operation' => 'cancel.manual',
     446                    'outcome'   => 'failed',
     447                    'method'    => __METHOD__,
     448                    'line'      => __LINE__,
     449                    'data'      => array(
     450                        'details' => 'ConvesioPay: Manual cancel network error - ' . $response->get_error_message() . ' (payment ' . $payment_id . ')'
     451                )));
    376452                return array( 'success' => false, 'message' => $response->get_error_message() );
    377453            }
     
    383459            if ( $response_code === 200 ) {
    384460                $response_data = json_decode( $response_body, true );
    385                 peachpay_log( 'info', 'ConvesioPay: Manual cancel success - payment ' . $payment_id );
     461                peachpay_log(
     462                'info',
     463                'Payments: Manual cancel success.',
     464                array(
     465                    'event'     => 'payments.convesiopay_admin.cancel.manual.success',
     466                    'component' => 'payments',
     467                    'feature'   => 'convesiopay_admin',
     468                    'operation' => 'cancel.manual',
     469                    'outcome'   => 'success',
     470                    'method'    => __METHOD__,
     471                    'line'      => __LINE__,
     472                    'data'      => array(
     473                        'details' => 'ConvesioPay: Manual cancel success - payment ' . $payment_id
     474                )));
    386475                return array( 'success' => true, 'data' => $response_data );
    387476            } else {
    388477                $error_data = json_decode( $response_body, true );
    389478                $error_message = $error_data['message'] ?? "HTTP $response_code error";
    390                 peachpay_log( 'error', 'ConvesioPay: Manual cancel API error - ' . $error_message . ' (payment ' . $payment_id . ')' );
     479                peachpay_log(
     480                'error',
     481                'Payments: Manual cancel failed.',
     482                array(
     483                    'event'     => 'payments.convesiopay_admin.cancel.manual.failed',
     484                    'component' => 'payments',
     485                    'feature'   => 'convesiopay_admin',
     486                    'operation' => 'cancel.manual',
     487                    'outcome'   => 'failed',
     488                    'method'    => __METHOD__,
     489                    'line'      => __LINE__,
     490                    'data'      => array(
     491                        'details' => 'ConvesioPay: Manual cancel API error - ' . $error_message . ' (payment ' . $payment_id . ')'
     492                )));
    391493                return array( 'success' => false, 'message' => $error_message );
    392494            }
  • peachpay-for-woocommerce/trunk/core/payments/convesiopay/gateways/class-peachpay-convesiopay-applepay-gateway.php

    r3465799 r3490786  
    274274                $amount_diff_cents = abs( $frontend_applepay_amount_cents - $order_amount_cents );
    275275                if ( $amount_diff_cents > 1 ) {
    276                     peachpay_log( 'warning', 'ConvesioPay: Apple Pay frontend amount differs from order total for order ' . $order->get_order_number() . ' (order_cents: ' . $order_amount_cents . ', frontend_cents: ' . $frontend_applepay_amount_cents . '). Rejecting so user re-authorizes.' );
     276                    peachpay_log(
     277                        'warning',
     278                        'Payments: Apple Pay process payment warning.',
     279                        array(
     280                            'event'     => 'payments.convesiopay_gateway.applepay.payment.warning',
     281                            'component' => 'payments',
     282                            'feature'   => 'convesiopay_gateway',
     283                            'operation' => 'applepay.payment',
     284                            'outcome'   => 'warning',
     285                            'method'    => __METHOD__,
     286                            'line'      => __LINE__,
     287                            'data'      => array(
     288                                'details' => 'ConvesioPay: Apple Pay frontend amount differs from order total for order ' . $order->get_order_number() . ' (order_cents: ' . $order_amount_cents . ', frontend_cents: ' . $frontend_applepay_amount_cents . '). Rejecting so user re-authorizes.'
     289                            )
     290                        )
     291                    );
    277292                    throw new Exception( __( 'Order total has changed. Please confirm the payment amount and try again.', 'peachpay-for-woocommerce' ) );
    278293                }
     
    330345            // Prepare request body - encode array to JSON string
    331346            $request_body = wp_json_encode( $payment_data );
    332             peachpay_log( 'debug', 'ConvesioPay: Apple Pay payment API request for order ' . $order->get_order_number() . ' (amount: ' . $order_amount . ' USD, order_cents: ' . $order_amount_cents . ', request_cents: ' . $request_amount_cents . ', line_items_sum_cents: ' . $line_items_sum_cents . ', order_total_tax: ' . $order->get_total_tax() . ', order_shipping_total: ' . $order->get_shipping_total() . ', order_shipping_tax: ' . $order->get_shipping_tax() . ', session_selected_method: ' . $selected_method_session . ', frontend_applepay_amount: ' . $frontend_applepay_amount . ')' );
     347            peachpay_log(
     348                'debug',
     349                'Payments: Apple Pay process payment api request debug.',
     350                array(
     351                    'event'     => 'payments.convesiopay_gateway.applepay.payment.debug',
     352                    'component' => 'payments',
     353                    'feature'   => 'convesiopay_gateway',
     354                    'operation' => 'applepay.payment',
     355                    'outcome'   => 'debug',
     356                    'method'    => __METHOD__,
     357                    'line'      => __LINE__,
     358                    'data'      => array(
     359                        'details' => $payment_data
     360                    )
     361                )
     362            );
    333363            if ( $line_items_sum_cents !== $request_amount_cents ) {
    334                 peachpay_log( 'warning', 'ConvesioPay: Apple Pay request amount differs from line item sum for order ' . $order->get_order_number() . ' (request_cents: ' . $request_amount_cents . ', line_items_sum_cents: ' . $line_items_sum_cents . ')' );
     364                peachpay_log(
     365                    'warning',
     366                    'Payments: Apple Pay process payment warning.',
     367                    array(
     368                        'event'     => 'payments.convesiopay_gateway.applepay.payment.warning',
     369                        'component' => 'payments',
     370                        'feature'   => 'convesiopay_gateway',
     371                        'operation' => 'applepay.payment',
     372                        'outcome'   => 'warning',
     373                        'method'    => __METHOD__,
     374                        'line'      => __LINE__,
     375                        'data'      => array(
     376                            'details' => 'ConvesioPay: Apple Pay request amount differs from line item sum for order ' . $order->get_order_number() . ' (request_cents: ' . $request_amount_cents . ', line_items_sum_cents: ' . $line_items_sum_cents . ')'
     377                        )
     378                    )
     379                );
    335380            }
    336381
     
    349394
    350395            if ( is_wp_error( $response ) ) {
    351                 peachpay_log( 'error', 'ConvesioPay: Apple Pay payment network error - ' . $response->get_error_message() . ' (order ' . $order->get_order_number() . ')' );
    352                 throw new Exception( 'Network error: ' . $response->get_error_message() );
     396                throw new Exception( 'ConvesioPay: Apple Pay payment network error - ' . $response->get_error_message() . ' (order ' . $order->get_order_number() . ')' );
    353397            }
    354398
     
    358402
    359403            if ( $response_code !== 200 ) {
    360                 peachpay_log( 'debug', 'ConvesioPay: Apple Pay REQUEST (HTTP ' . $response_code . ') ' . $api_url . ' => ' . wp_json_encode( $payment_data ) );
    361                 peachpay_log( 'debug', 'ConvesioPay: Apple Pay RESPONSE (HTTP ' . $response_code . ') => ' . $response_body );
    362                 peachpay_log( 'error', 'ConvesioPay: Apple Pay payment API error HTTP ' . $response_code . ' (order ' . $order->get_order_number() . ')' );
    363404                // Extract error message from response
    364405                $error_message = 'ConvesioPay API error (HTTP ' . $response_code . ')';
     
    378419
    379420            if ( empty( $status ) || empty( $payment_id ) ) {
    380                 peachpay_log( 'error', 'ConvesioPay: Apple Pay payment invalid response - missing status or id (order ' . $order->get_order_number() . ')' );
    381                 throw new Exception( 'Invalid response from ConvesioPay' );
     421                throw new Exception( 'Invalid response from ConvesioPay status: ' . $status . ', payment_id: ' . $payment_id );
    382422            }
    383423
     
    448488                $order->save();
    449489
    450                 peachpay_log( 'info', 'ConvesioPay: Apple Pay payment success - order ' . $order->get_order_number() . ', payment_id ' . $payment_id . ', status ' . $status );
     490                $peachpay_log_type = "info";
     491                $peachpay_log_message = 'ConvesioPay ConvesioPay Apple Pay process payment success for order id - ' . $order_id;
     492                if ( $status === 'Refused' || $status === 'Blocked' ) {
     493                    $peachpay_log_type = "error";
     494                    $peachpay_log_message = 'ConvesioPay ConvesioPay Apple Pay process payment ' . strtolower($status) . ' for order id - ' . $order_id;
     495                }
     496                peachpay_log(
     497                    $peachpay_log_type,
     498                    $peachpay_log_message,
     499                    array(
     500                        'event'     => 'payments.convesiopay_gateway.applepay.payment.' . strtolower($status),
     501                        'component' => 'payments',
     502                        'feature'   => 'convesiopay_gateway',
     503                        'operation' => 'applepay.payment',
     504                        'outcome'   => strtolower($status),
     505                        'method'    => __METHOD__,
     506                        'line'      => __LINE__,
     507                        'data'      => array(
     508                            'response_data' => $response_data
     509                        )
     510                    )
     511                );
     512
    451513                return array(
    452514                    'result'   => 'success',
     
    454516                );
    455517            } else {
    456                 peachpay_log( 'error', 'ConvesioPay: Apple Pay payment failed - status ' . $status . ' (order ' . $order->get_order_number() . ')' );
    457518                throw new Exception( 'Payment failed with status: ' . $status );
    458519            }
    459520        } catch ( Exception $e ) {
    460             peachpay_log( 'error', 'ConvesioPay: Apple Pay payment exception - ' . $e->getMessage() . ' (order ' . $order->get_order_number() . ')' );
     521            peachpay_log(
     522                'error',
     523                'Payments: Apple Pay process payment failed.',
     524                array(
     525                    'event'     => 'payments.convesiopay_gateway.applepay.payment.failed',
     526                    'component' => 'payments',
     527                    'feature'   => 'convesiopay_gateway',
     528                    'operation' => 'applepay.payment',
     529                    'outcome'   => 'failed',
     530                    'method'    => __METHOD__,
     531                    'line'      => __LINE__,
     532                    'data'      => array(
     533                        'details' => 'ConvesioPay: Apple Pay payment exception - ' . $e->getMessage() . ' (order ' . $order->get_order_number() . ')'
     534                    )
     535                )
     536            );
    461537            $order->add_order_note(
    462538                sprintf(
  • peachpay-for-woocommerce/trunk/core/payments/convesiopay/gateways/class-peachpay-convesiopay-card-gateway.php

    r3486614 r3490786  
    1616 */
    1717class PeachPay_ConvesioPay_Card_Gateway extends PeachPay_Payment_Gateway {
     18    /**
     19     * Track whether the renewal hook has been registered.
     20     *
     21     * @var bool
     22     */
     23    private static $renewal_hook_registered = false;
     24
    1825    /**
    1926     * Track if gateway was properly initialized
     
    8693        add_action( 'admin_footer', array( $this, 'inject_admin_card_icons' ) );
    8794       
    88         // Subscription renewal support
    89         $gateway = $this;
    90         add_action(
    91             'woocommerce_scheduled_subscription_payment_' . $this->id,
    92             function ( $renewal_total, $renewal_order ) use ( $gateway ) {
    93                 if ( ! function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ) {
    94                     return;
    95                 }
    96                 $subscriptions = wcs_get_subscriptions_for_renewal_order( $renewal_order );
    97                 $subscription  = array_pop( $subscriptions );
    98                 if ( ! $subscription ) {
    99                     return;
    100                 }
    101                 $parent_order = wc_get_order( $subscription->get_parent_id() );
    102                 $gateway->process_subscription_renewal( $parent_order, $renewal_order, $renewal_total );
    103             },
    104             10,
    105             2
    106         );
     95        // Subscription renewal support.
     96        $this->register_subscription_renewal_hook();
    10797       
    10898        // Initialize form fields
     
    110100        // Mark as initialized
    111101        $this->initialized = true;
     102    }
     103
     104    /**
     105     * Register subscription renewal hook once per request.
     106     */
     107    private function register_subscription_renewal_hook() {
     108        if ( self::$renewal_hook_registered ) {
     109            return;
     110        }
     111        add_action(
     112            'woocommerce_scheduled_subscription_payment_' . $this->id,
     113            array( $this, 'handle_subscription_renewal_payment' ),
     114            10,
     115            2
     116        );
     117        self::$renewal_hook_registered = true;
     118    }
     119
     120    /**
     121     * Handle scheduled subscription payment for card ConvesioPay gateway.
     122     *
     123     * @param float    $renewal_total Renewal amount.
     124     * @param WC_Order $renewal_order Renewal order.
     125     */
     126    public function handle_subscription_renewal_payment( $renewal_total, $renewal_order ) {
     127        if ( ! function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ) {
     128            peachpay_log(
     129                'error',
     130                'Payments: Subscription renewal failed.',
     131                array(
     132                    'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     133                    'component' => 'payments',
     134                    'feature'   => 'convesiopay_gateway',
     135                    'operation' => 'subscription.renewal',
     136                    'outcome'   => 'failed',
     137                    'line'     => __LINE__,
     138                    'function' => __FUNCTION__,
     139                    'file'     => __FILE__,
     140                    'class'    => __CLASS__,
     141                    'method'   => __METHOD__,
     142                    'data'     => array(
     143                        'renewal_total' => $renewal_total,
     144                        'details' => 'function wcs_get_subscriptions_for_renewal_order not found',
     145                    ),
     146                )
     147            );
     148            return;
     149        }
     150        $subscriptions = wcs_get_subscriptions_for_renewal_order( $renewal_order );
     151        $subscription  = array_pop( $subscriptions );
     152        if ( ! $subscription ) {
     153            peachpay_log(
     154                'error',
     155                'Convesiopay Card Subscription renewal failed - no subscription found for renewal order',
     156                array(
     157                    'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     158                    'component' => 'payments',
     159                    'feature'   => 'convesiopay_gateway',
     160                    'operation' => 'subscription.renewal',
     161                    'outcome'   => 'failed',
     162                    'line'     => __LINE__,
     163                    'function' => __FUNCTION__,
     164                    'file'     => __FILE__,
     165                    'class'    => __CLASS__,
     166                    'method'   => __METHOD__,
     167                    'data'     => array(
     168                        'renewal_total' => $renewal_total,
     169                        'details' => 'no subscription found for renewal order',
     170                    ),
     171                )
     172            );
     173            return;
     174        }
     175        $parent_order = wc_get_order( $subscription->get_parent_id() );
     176        if ( ! $parent_order ) {
     177            peachpay_log(
     178                'error',
     179                'Convesiopay Card Subscription renewal failed - no parent order found for subscription',
     180                array(
     181                    'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     182                    'component' => 'payments',
     183                    'feature'   => 'convesiopay_gateway',
     184                    'operation' => 'subscription.renewal',
     185                    'outcome'   => 'failed',
     186                    'line'     => __LINE__,
     187                    'function' => __FUNCTION__,
     188                    'file'     => __FILE__,
     189                    'class'    => __CLASS__,
     190                    'method'   => __METHOD__,
     191                    'data'     => array(
     192                        'renewal_total'   => $renewal_total,
     193                        'parent_order_id' => $subscription->get_parent_id(),
     194                        'details' => 'no parent order found for subscription',
     195                    ),
     196                )
     197            );
     198            return;
     199        }
     200
     201        peachpay_log(
     202            'debug',
     203            'ConvesioPay Card Subscription renewal debug for subscription id - ' . $subscription->get_id(),
     204            array(
     205                'event'     => 'payments.convesiopay_gateway.subscription.renewal.debug',
     206                'component' => 'payments',
     207                'feature'   => 'convesiopay_gateway',
     208                'operation' => 'subscription.renewal',
     209                'outcome'   => 'debug',
     210                'line'     => __LINE__,
     211                'function' => __FUNCTION__,
     212                'file'     => __FILE__,
     213                'class'    => __CLASS__,
     214                'method'   => __METHOD__,
     215                'data'     => array(
     216                    'renewal_total' => $renewal_total
     217                ),
     218            )
     219        );
     220
     221        $this->process_subscription_renewal( $parent_order, $renewal_order, $renewal_total );
     222       
     223        peachpay_log(
     224            'debug',
     225            'ConvesioPay Card Subscription renewal debug for subscription id - ' . $subscription->get_id() . ' completed',
     226            array(
     227                'event'     => 'payments.convesiopay_gateway.subscription.renewal.debug',
     228                'component' => 'payments',
     229                'feature'   => 'convesiopay_gateway',
     230                'operation' => 'subscription.renewal',
     231                'outcome'   => 'debug',
     232                'line'     => __LINE__,
     233                'function' => __FUNCTION__,
     234                'file'     => __FILE__,
     235                'class'    => __CLASS__,
     236                'method'   => __METHOD__,
     237            )
     238        );
    112239    }
    113240
     
    246373    private function create_fallback_transaction_id() {
    247374        $transaction_id = 'cvp_card_tx_' . time() . '_' . wp_rand( 1000, 9999 );
    248         peachpay_log( 'debug', 'ConvesioPay: Local fallback transaction id - ' . $transaction_id );
    249375        return $transaction_id;
    250376    }
     
    739865            // Make API call to ConvesioPay
    740866            $api_url = $config['api_url'] . '/payments';
    741             peachpay_log( 'debug', 'ConvesioPay: Card payment API request for order ' . $order->get_order_number() . ' (amount: ' . $order_amount . ' USD)' );
     867            peachpay_log(
     868                'debug',
     869                'ConvesioPay Card process payment debug for order id - ' . $order_id,
     870                array(
     871                    'event'     => 'payments.convesiopay_gateway.card.payment.debug',
     872                    'component' => 'payments',
     873                    'feature'   => 'convesiopay_gateway',
     874                    'operation' => 'card.payment',
     875                    'outcome'   => 'debug',
     876                    'line'      => __LINE__,
     877                    'function'  => __FUNCTION__,
     878                    'file'      => __FILE__,
     879                    'class'     => __CLASS__,
     880                    'method'    => __METHOD__,
     881                    'data'      => array(
     882                        'api_url' => $api_url,
     883                        'payment_data' => $payment_data,
     884                    ),
     885                )
     886            );
    742887
    743888            $response = wp_remote_post( $api_url, array(
     
    752897
    753898            if ( is_wp_error( $response ) ) {
    754                 peachpay_log( 'error', 'ConvesioPay: Card payment network error - ' . $response->get_error_message() . ' (order ' . $order->get_order_number() . ')' );
    755899                throw new Exception( 'Network error: ' . $response->get_error_message() );
    756900            }
     
    761905
    762906            if ( $response_code !== 200 ) {
    763                 peachpay_log( 'debug', 'ConvesioPay: Card REQUEST (HTTP ' . $response_code . ') ' . $api_url . ' => ' . wp_json_encode( $payment_data ) );
    764                 peachpay_log( 'debug', 'ConvesioPay: Card RESPONSE (HTTP ' . $response_code . ') => ' . $response_body );
    765                 peachpay_log( 'error', 'ConvesioPay: Card payment API error HTTP ' . $response_code . ' - ' . substr( $response_body, 0, 300 ) . ' (order ' . $order->get_order_number() . ')' );
    766907                throw new Exception( 'ConvesioPay API error (HTTP ' . $response_code . '): ' . $response_body );
    767908            }
     
    781922
    782923            if ( empty( $status ) || empty( $transaction_id ) ) {
    783                 peachpay_log( 'error', 'ConvesioPay: Card payment invalid response - missing status or id (order ' . $order->get_order_number() . ')' );
     924                peachpay_log(
     925                    'error',
     926                    'ConvesioPay Card process payment failed - invalid response for order id - ' . $order_id,
     927                    array(
     928                        'event'     => 'payments.convesiopay_gateway.card.payment.failed',
     929                        'component' => 'payments',
     930                        'feature'   => 'convesiopay_gateway',
     931                        'operation' => 'card.payment',
     932                        'outcome'   => 'failed',
     933                        'method'    => __METHOD__,
     934                        'line'      => __LINE__,
     935                        'data'      => array(
     936                            'response_data' => $response_data
     937                        )
     938                    )
     939                );
    784940                throw new Exception( 'Invalid response from ConvesioPay' );
    785941            }
     
    8611017                $order->save();
    8621018
    863                 peachpay_log( 'info', 'ConvesioPay: Card payment success - order ' . $order->get_order_number() . ', payment_id ' . $transaction_id . ', status ' . $status );
     1019                $peachpay_log_type = "info";
     1020                $peachpay_log_message = 'ConvesioPay Card process payment success for order id - ' . $order_id;
     1021                if ( $status === 'Refused' || $status === 'Blocked' ) {
     1022                    $peachpay_log_type = "error";
     1023                    $peachpay_log_message = 'ConvesioPay Card process payment ' . strtolower($status) . ' for order id - ' . $order_id;
     1024                }
     1025                peachpay_log(
     1026                    $peachpay_log_type,
     1027                    $peachpay_log_message,
     1028                    array(
     1029                        'event'     => 'payments.convesiopay_gateway.card.payment.' . strtolower($status),
     1030                        'component' => 'payments',
     1031                        'feature'   => 'convesiopay_gateway',
     1032                        'operation' => 'card.payment',
     1033                        'outcome'   => strtolower($status),
     1034                        'method'    => __METHOD__,
     1035                        'line'      => __LINE__,
     1036                        'data'      => array(
     1037                            'response_data' => $response_data
     1038                        )
     1039                    )
     1040                );
    8641041                return array(
    8651042                    'result'   => 'success',
     
    8671044                );
    8681045            } else {
    869                 peachpay_log( 'error', 'ConvesioPay: Card payment failed - status ' . $status . ' (order ' . $order->get_order_number() . ')' );
     1046                peachpay_log(
     1047                    'error',
     1048                    'ConvesioPay Card process payment failed - status ' . $status . ' for order id - ' . $order_id,
     1049                    array(
     1050                        'event'     => 'payments.convesiopay_gateway.card.payment.failed',
     1051                        'component' => 'payments',
     1052                        'feature'   => 'convesiopay_gateway',
     1053                        'operation' => 'card.payment',
     1054                        'outcome'   => 'failed',
     1055                        'method'    => __METHOD__,
     1056                        'line'      => __LINE__,
     1057                        'data'      => array(
     1058                            'response_data' => $response_data
     1059                        )
     1060                    )
     1061                );
    8701062                throw new Exception( 'Payment failed with status: ' . $status );
    8711063            }
    8721064
    8731065        } catch ( Exception $e ) {
    874             peachpay_log( 'error', 'ConvesioPay: Card payment exception - ' . $e->getMessage() . ' (order ' . $order->get_order_number() . ')' );
     1066            peachpay_log(
     1067                'error',
     1068                'ConvesioPay Card process payment failed - exception',
     1069                array(
     1070                    'event'     => 'payments.convesiopay_gateway.card.payment.failed',
     1071                    'component' => 'payments',
     1072                        'feature'   => 'convesiopay_gateway',
     1073                        'operation' => 'card.payment',
     1074                        'outcome'   => 'failed',
     1075                        'line'      => __LINE__,
     1076                        'function'  => __FUNCTION__,
     1077                        'file'      => __FILE__,
     1078                        'class'     => __CLASS__,
     1079                        'method'    => __METHOD__,
     1080                        'data'      => array(
     1081                            'message' => $e->getMessage(),
     1082                            'code' => $e->getCode(),
     1083                            'file' => $e->getFile(),
     1084                            'line' => $e->getLine(),
     1085                            'trace' => $e->getTraceAsString(),
     1086                        )
     1087                    )
     1088                );
    8751089            $order->add_order_note( sprintf( __( 'ConvesioPay payment failed: %s', 'peachpay-for-woocommerce' ), $e->getMessage() ) );
    8761090            wc_add_notice( __( 'Payment failed: ', 'peachpay-for-woocommerce' ) . $e->getMessage(), 'error' );
     
    9541168
    9551169            if ( ! $payment_id ) {
    956                 peachpay_log( 'error', 'ConvesioPay: Refund - payment ID not found for order ' . $order->get_order_number() );
     1170                peachpay_log(
     1171                    'error',
     1172                    'ConvesioPay Card process refund failed - payment ID not found for order id - ' . $order_id,
     1173                    array(
     1174                        'event'     => 'payments.convesiopay_gateway.refund.failed',
     1175                        'component' => 'payments',
     1176                        'feature'   => 'convesiopay_gateway',
     1177                        'operation' => 'refund',
     1178                        'outcome'   => 'failed',
     1179                        'method'    => __METHOD__,
     1180                        'line'      => __LINE__,
     1181                    )
     1182                );
    9571183                return new WP_Error( 'convesiopay_refund_error', __( 'Payment ID not found for this order.', 'peachpay-for-woocommerce' ) );
    9581184            }
     
    9761202            // Build refund endpoint URL
    9771203            $refund_endpoint = $config['api_url'] . '/payments/' . $payment_id . '/refund';
    978             peachpay_log( 'debug', 'ConvesioPay: Refund API request for order ' . $order->get_order_number() . ', payment ' . $payment_id . ', amount ' . $refund_data['amount'] . ' ' . $refund_data['currency'] );
     1204            peachpay_log(
     1205                'debug',
     1206                'ConvesioPay Card process refund debug for order id - ' . $order_id,
     1207                array(
     1208                    'event'     => 'payments.convesiopay_gateway.refund.debug',
     1209                    'component' => 'payments',
     1210                    'feature'   => 'convesiopay_gateway',
     1211                    'operation' => 'refund',
     1212                    'outcome'   => 'debug',
     1213                    'method'    => __METHOD__,
     1214                    'line'      => __LINE__,
     1215                    'data'      => array(
     1216                        'api_url' => $refund_endpoint,
     1217                        'request_data' => $refund_data,
     1218                    )
     1219                )
     1220            );
    9791221
    9801222            // Add order note for refund request
     
    9981240
    9991241            if ( is_wp_error( $response ) ) {
    1000                 peachpay_log( 'error', 'ConvesioPay: Refund network error - ' . $response->get_error_message() . ' (order ' . $order->get_order_number() . ', payment ' . $payment_id . ')' );
     1242                peachpay_log(
     1243                    'error',
     1244                    'ConvesioPay Card process refund failed - network error for order id - ' . $order_id,
     1245                    array(
     1246                        'event'     => 'payments.convesiopay_gateway.refund.failed',
     1247                        'component' => 'payments',
     1248                        'feature'   => 'convesiopay_gateway',
     1249                        'operation' => 'refund',
     1250                        'outcome'   => 'failed',
     1251                        'line'      => __LINE__,
     1252                        'function'  => __FUNCTION__,
     1253                        'file'      => __FILE__,
     1254                        'class'     => __CLASS__,
     1255                        'method'    => __METHOD__,
     1256                        'data'      => array(
     1257                            'error_message' => $response->get_error_message()
     1258                        )
     1259                    )
     1260                );
    10011261                $order->add_order_note( sprintf(
    10021262                    __( 'ConvesioPay refund response: Network error - %s', 'peachpay-for-woocommerce' ),
     
    10121272            if ( $response_code !== 200 ) {
    10131273                $error_message = isset( $response_data['message'] ) ? $response_data['message'] : 'Refund failed (HTTP ' . $response_code . ')';
    1014                 peachpay_log( 'error', 'ConvesioPay: Refund API error - ' . $error_message . ' (order ' . $order->get_order_number() . ', payment ' . $payment_id . ')' );
     1274                peachpay_log(
     1275                    'error',
     1276                    'ConvesioPay Card process refund failed - API error for order id - ' . $order_id,
     1277                    array(
     1278                        'event'     => 'payments.convesiopay_gateway.refund.failed',
     1279                        'component' => 'payments',
     1280                        'feature'   => 'convesiopay_gateway',
     1281                        'operation' => 'refund',
     1282                        'outcome'   => 'failed',
     1283                        'line'      => __LINE__,
     1284                        'function'  => __FUNCTION__,
     1285                        'file'      => __FILE__,
     1286                        'class'     => __CLASS__,
     1287                        'method'    => __METHOD__,
     1288                        'line'      => __LINE__,
     1289                        'data'      => array(
     1290                            'error_message' => $error_message
     1291                        )
     1292                    )
     1293                );
    10151294                return new WP_Error( 'convesiopay_refund_error', $error_message );
    10161295            }
     
    10181297            // Refund successful - extract refund details from response
    10191298            $refund_id = isset( $response_data['id'] ) ? $response_data['id'] : '';
    1020             peachpay_log( 'info', 'ConvesioPay: Refund success - order ' . $order->get_order_number() . ', refund_id ' . $refund_id );
     1299            peachpay_log(
     1300                'info',
     1301                'ConvesioPay Card process refund success for order id - ' . $order_id,
     1302                array(
     1303                    'event'     => 'payments.convesiopay_gateway.refund.success',
     1304                    'component' => 'payments',
     1305                    'feature'   => 'convesiopay_gateway',
     1306                    'operation' => 'refund',
     1307                    'outcome'   => 'success',
     1308                    'line'      => __LINE__,
     1309                    'function'  => __FUNCTION__,
     1310                    'file'      => __FILE__,
     1311                    'class'     => __CLASS__,
     1312                    'method'    => __METHOD__,
     1313                    'data'      => array(
     1314                        'response_data' => $response_data
     1315                    )
     1316                )
     1317            );
    10211318           
    10221319            // Add detailed order note
     
    10451342
    10461343        } catch ( Exception $e ) {
    1047             peachpay_log( 'error', 'ConvesioPay: Refund exception - ' . $e->getMessage() . ' (order ' . $order->get_order_number() . ')' );
     1344            peachpay_log(
     1345                'error',
     1346                'ConvesioPay Card process refund failed - exception',
     1347                array(
     1348                    'event'     => 'payments.convesiopay_gateway.refund.failed',
     1349                    'component' => 'payments',
     1350                    'feature'   => 'convesiopay_gateway',
     1351                    'operation' => 'refund',
     1352                    'outcome'   => 'failed',
     1353                    'method'    => __METHOD__,
     1354                    'line'      => __LINE__,
     1355                    'function'  => __FUNCTION__,
     1356                    'file'      => __FILE__,
     1357                    'class'     => __CLASS__,
     1358                    'method'    => __METHOD__,
     1359                    'data'      => array(
     1360                        'message' => $e->getMessage(),
     1361                        'code' => $e->getCode(),
     1362                        'file' => $e->getFile(),
     1363                        'line' => $e->getLine(),
     1364                    )
     1365                )
     1366            );
    10481367            return new WP_Error( 'convesiopay_refund_error', $e->getMessage() );
    10491368        }
     
    10581377     */
    10591378    private function find_payment_by_order_number( $order_number, $config ) {
    1060         peachpay_log( 'debug', 'ConvesioPay: GET /payments/list API request for order_number ' . $order_number );
     1379        peachpay_log(
     1380                'debug',
     1381                'ConvesioPay find payment by order number debug for order number - ' . $order_number,
     1382                array(
     1383                'event'     => 'payments.convesiopay_gateway.event.debug',
     1384                'component' => 'payments',
     1385                'feature'   => 'convesiopay_gateway',
     1386                'operation' => 'event',
     1387                'outcome'   => 'debug',
     1388                'method'    => __METHOD__,
     1389                'line'      => __LINE__,
     1390                'data'      => array(
     1391                    'api_url' => $config['api_url'] . '/payments/list?orderNumber=' . urlencode( $order_number )
     1392                )));
    10611393
    10621394        // Make API call to ConvesioPay to find payment by order number
     
    10701402
    10711403        if ( is_wp_error( $response ) ) {
    1072             peachpay_log( 'error', 'ConvesioPay: GET /payments/list network error - ' . $response->get_error_message() . ' (order_number ' . $order_number . ')' );
     1404            peachpay_log(
     1405                'error',
     1406                'ConvesioPay find payment by order number failed - network error for order number - ' . $order_number,
     1407                array(
     1408                    'event'     => 'payments.convesiopay_gateway.find_payment_by_order_number.failed',
     1409                    'component' => 'payments',
     1410                    'feature'   => 'convesiopay_gateway',
     1411                    'operation' => 'find_payment_by_order_number',
     1412                    'outcome'   => 'failed',
     1413                    'line'      => __LINE__,
     1414                    'function'  => __FUNCTION__,
     1415                    'file'      => __FILE__,
     1416                    'class'     => __CLASS__,
     1417                    'method'    => __METHOD__,
     1418                    'data'      => array(
     1419                        'error_message' => $response->get_error_message()
     1420                    )
     1421                )
     1422            );
    10731423            return false;
    10741424        }
     
    10791429
    10801430        if ( $response_code !== 200 || empty( $response_data['payments'] ) ) {
    1081             peachpay_log( 'warning', 'ConvesioPay: GET /payments/list - HTTP ' . $response_code . ' or no payments (order_number ' . $order_number . ')' );
     1431            peachpay_log(
     1432                'warning',
     1433                'ConvesioPay find payment by order number warning - HTTP ' . $response_code . ' or no payments (order_number ' . $order_number . ')',
     1434                array(
     1435                    'event'     => 'payments.convesiopay_gateway.find_payment_by_order_number.warning',
     1436                    'component' => 'payments',
     1437                    'feature'   => 'convesiopay_gateway',
     1438                    'operation' => 'find_payment_by_order_number',
     1439                    'outcome'   => 'warning',
     1440                    'line'      => __LINE__,
     1441                    'function'  => __FUNCTION__,
     1442                    'file'      => __FILE__,
     1443                    'class'     => __CLASS__,
     1444                    'method'    => __METHOD__,
     1445                    'data'      => array(
     1446                        'response_code' => $response_code,
     1447                        'response_body' => $response_body,
     1448                        'response_data' => $response_data
     1449                    )
     1450                )
     1451            );
    10821452            return false;
    10831453        }
     
    10851455        $payment_id = $response_data['payments'][0]['id'] ?? false;
    10861456        if ( $payment_id ) {
    1087             peachpay_log( 'info', 'ConvesioPay: GET /payments/list found payment ' . $payment_id . ' for order_number ' . $order_number );
     1457            peachpay_log(
     1458                'info',
     1459                'ConvesioPay find payment by order number success for order number - ' . $order_number,
     1460                array(
     1461                    'event'     => 'payments.convesiopay_gateway.find_payment_by_order_number.success',
     1462                    'component' => 'payments',
     1463                    'feature'   => 'convesiopay_gateway',
     1464                    'operation' => 'find_payment_by_order_number',
     1465                    'outcome'   => 'success',
     1466                    'line'      => __LINE__,
     1467                    'function'  => __FUNCTION__,
     1468                    'file'      => __FILE__,
     1469                    'class'     => __CLASS__,
     1470                    'method'    => __METHOD__,
     1471                    'data'      => array(
     1472                        'response_data' => $response_data
     1473                    )
     1474                )
     1475            );
    10881476        }
    10891477        return $payment_id;
     
    12501638            // Idempotency: do not charge if this renewal order is already paid (prevents double charge from duplicate hooks or webhook + sync race).
    12511639            if ( $renewal_order->has_status( array( 'processing', 'completed' ) ) ) {
    1252                 peachpay_log( 'debug', 'ConvesioPay: Stored-card renewal skipped - order ' . $renewal_order->get_order_number() . ' already paid (status: ' . $renewal_order->get_status() . ').' );
     1640                peachpay_log(
     1641                    'warning',
     1642                    'ConvesioPay Card Subscription renewal warning - renewal order id - ' . $renewal_order->get_id() . ' already paid (status: ' . $renewal_order->get_status() . ')',
     1643                    array(
     1644                        'event'     => 'payments.convesiopay_gateway.subscription.renewal.warning',
     1645                        'component' => 'payments',
     1646                        'feature'   => 'convesiopay_gateway',
     1647                        'operation' => 'subscription.renewal',
     1648                        'outcome'   => 'warning',
     1649                        'line'      => __LINE__,
     1650                        'function'  => __FUNCTION__,
     1651                        'file'      => __FILE__,
     1652                        'class'     => __CLASS__,
     1653                        'method'    => __METHOD__,
     1654                        'data'      => array(
     1655                            'order_id'     => $renewal_order->get_id(),
     1656                            'order_status' => $renewal_order->get_status(),
     1657                            'order_number' => $renewal_order->get_order_number(),
     1658                            'renewal_total'=> isset( $renewal_total ) ? $renewal_total : null
     1659                        ),
     1660                    )
     1661                );
    12531662                return;
    12541663            }
     1664
    12551665            if ( ! empty( $renewal_order->get_meta( '_convesiopay_payment_id' ) ) ) {
    1256                 peachpay_log( 'debug', 'ConvesioPay: Stored-card renewal skipped - order ' . $renewal_order->get_order_number() . ' already has ConvesioPay payment ID.' );
     1666                peachpay_log(
     1667                    'warning',
     1668                    'ConvesioPay Card Subscription renewal failed - renewal order id - ' . $renewal_order->get_id() . ' already has a payment id',
     1669                    array(
     1670                        'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     1671                        'component' => 'payments',
     1672                        'feature'   => 'convesiopay_gateway',
     1673                        'operation' => 'subscription.renewal',
     1674                        'outcome'   => 'failed',
     1675                        'line'      => __LINE__,
     1676                        'function'  => __FUNCTION__,
     1677                        'file'      => __FILE__,
     1678                        'class'     => __CLASS__,
     1679                        'method'    => __METHOD__,
     1680                        'data'      => array(
     1681                            'convesiopay_payment_id' => $renewal_order->get_meta( '_convesiopay_payment_id' ),
     1682                            'order_id' => $renewal_order->get_id(),
     1683                            'order_status' => $renewal_order->get_status(),
     1684                            'order_number' => $renewal_order->get_order_number(),
     1685                            'renewal_total'=> isset( $renewal_total ) ? $renewal_total : null
     1686                        ),
     1687                    )
     1688                );
    12571689                return;
    1258             }
    1259 
    1260             // If subscription already has another completed renewal order created recently (e.g. duplicate scheduled action created two renewal orders), skip charging this one to avoid double charge.
    1261             if ( function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ) {
    1262                 $subscriptions = wcs_get_subscriptions_for_renewal_order( $renewal_order );
    1263                 $subscription  = is_array( $subscriptions ) ? array_pop( $subscriptions ) : null;
    1264                 if ( $subscription && is_callable( array( $subscription, 'get_related_orders' ) ) ) {
    1265                     $renewal_order_ids = $subscription->get_related_orders( 'ids', 'renewal' );
    1266                     $recent_cutoff     = strtotime( '-2 hours' );
    1267                     foreach ( (array) $renewal_order_ids as $other_id ) {
    1268                         if ( (int) $other_id === (int) $renewal_order->get_id() ) {
    1269                             continue;
    1270                         }
    1271                         $other_order = wc_get_order( $other_id );
    1272                         if ( ! $other_order || ! $other_order->has_status( array( 'processing', 'completed' ) ) ) {
    1273                             continue;
    1274                         }
    1275                         $created = $other_order->get_date_created();
    1276                         if ( $created && $created->getTimestamp() >= $recent_cutoff ) {
    1277                             peachpay_log( 'info', 'ConvesioPay: Stored-card renewal skipped - subscription already has completed renewal order #' . $other_order->get_order_number() . ' (possible duplicate scheduled action). Order ' . $renewal_order->get_order_number() . ' not charged.' );
    1278                             $renewal_order->add_order_note( sprintf(
    1279                                 __( 'Renewal payment skipped: subscription already has a completed renewal order #%s. This may be a duplicate; no charge was made.', 'peachpay-for-woocommerce' ),
    1280                                 $other_order->get_order_number()
    1281                             ) );
    1282                             return;
    1283                         }
    1284                     }
    1285                 }
    12861690            }
    12871691
     
    12911695
    12921696            if ( empty( $customer_id ) || empty( $stored_payment_method_id ) ) {
    1293                 peachpay_log( 'error', 'ConvesioPay: Stored-card renewal - missing customer_id or stored_payment_method_id (order ' . $renewal_order->get_order_number() . ')' );
    1294                 throw new Exception( __( 'Missing stored payment method for subscription renewal.', 'peachpay-for-woocommerce' ) );
     1697                peachpay_log(
     1698                    'error',
     1699                    'ConvesioPay Card Subscription renewal failed - missing customer id or stored payment method id',
     1700                    array(
     1701                        'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     1702                        'component' => 'payments',
     1703                        'feature'   => 'convesiopay_gateway',
     1704                        'operation' => 'subscription.renewal',
     1705                        'outcome'   => 'failed',
     1706                        'line'      => __LINE__,
     1707                        'function'  => __FUNCTION__,
     1708                        'file'      => __FILE__,
     1709                        'class'     => __CLASS__,
     1710                        'method'    => __METHOD__,
     1711                        'data'      => array(
     1712                            'parent_order_id' => $parent_order->get_id(),
     1713                            'renewal_order_id' => $renewal_order->get_id(),
     1714                            'customer_id' => $customer_id,
     1715                            'stored_payment_method_id' => $stored_payment_method_id,
     1716                        ),
     1717                    )
     1718                );
     1719                throw new Exception( __( 'Missing customer id or stored payment method id for subscription renewal.', 'peachpay-for-woocommerce' ) );
    12951720            }
    12961721
    12971722            $config = $this->get_convesiopay_config();
    12981723            if ( empty( $config['secret_key'] ) ) {
    1299                 peachpay_log( 'error', 'ConvesioPay: Stored-card renewal - ConvesioPay not configured (order ' . $renewal_order->get_order_number() . ')' );
    1300                 throw new Exception( __( 'ConvesioPay is not properly configured.', 'peachpay-for-woocommerce' ) );
     1724                throw new Exception( __( 'ConvesioPay is not properly configured. Missing secret key.', 'peachpay-for-woocommerce' ) );
    13011725            }
    13021726
     
    13161740
    13171741            // Call ConvesioPay Card On File endpoint
    1318             peachpay_log( 'debug', 'ConvesioPay: POST /payments/stored-card API request for renewal order ' . $renewal_order->get_order_number() );
     1742            peachpay_log(
     1743                'debug',
     1744                'Convesiopay Card Subscription renewal api request debug - renewal order id - ' . $renewal_order->get_id(),
     1745                array(
     1746                    'event'     => 'payments.convesiopay_gateway.subscription.renewal.debug',
     1747                    'component' => 'payments',
     1748                    'feature'   => 'convesiopay_gateway',
     1749                    'operation' => 'subscription.renewal',
     1750                    'outcome'   => 'debug',
     1751                    'line'      => __LINE__,
     1752                    'function'  => __FUNCTION__,
     1753                    'file'      => __FILE__,
     1754                    'class'     => __CLASS__,
     1755                    'method'    => __METHOD__,
     1756                    'data'      => array(
     1757                        'api_url' => $config['api_url'] . '/payments/stored-card',
     1758                        'request_data' => $request_data,
     1759                    ),
     1760                )
     1761            );
    13191762
    13201763            $response = wp_remote_post( $config['api_url'] . '/payments/stored-card', array(
     
    13281771
    13291772            if ( is_wp_error( $response ) ) {
    1330                 peachpay_log( 'error', 'ConvesioPay: Stored-card renewal network error - ' . $response->get_error_message() . ' (order ' . $renewal_order->get_order_number() . ')' );
     1773                peachpay_log(
     1774                    'error',
     1775                    'ConvesioPay Card Subscription renewal failed - network error for renewal order id - ' . $renewal_order->get_id(),
     1776                    array(
     1777                        'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     1778                        'component' => 'payments',
     1779                        'feature'   => 'convesiopay_gateway',
     1780                        'operation' => 'subscription.renewal',
     1781                        'outcome'   => 'failed',
     1782                        'line'      => __LINE__,
     1783                        'function'  => __FUNCTION__,
     1784                        'file'      => __FILE__,
     1785                        'class'     => __CLASS__,
     1786                        'method'    => __METHOD__,
     1787                        'data'      => array(
     1788                            'request_data' => $request_data,
     1789                            'error_message' =>  $response->get_error_message(),
     1790                        ),
     1791                    )
     1792                );
    13311793                throw new Exception( 'Network error: ' . $response->get_error_message() );
    13321794            }
     
    13411803
    13421804            if ( $response_code === 200 && in_array( $status, $success_statuses, true ) ) {
    1343                 peachpay_log( 'info', 'ConvesioPay: Stored-card renewal success - order ' . $renewal_order->get_order_number() . ', payment_id ' . $payment_id . ', status ' . $status );
     1805                peachpay_log(
     1806                    'info',
     1807                    'ConvesioPay Card Subscription renewal success - renewal order id - ' . $renewal_order->get_id(),
     1808                    array(
     1809                        'event'     => 'payments.convesiopay_gateway.subscription.renewal.success',
     1810                        'component' => 'payments',
     1811                        'feature'   => 'convesiopay_gateway',
     1812                        'operation' => 'subscription.renewal',
     1813                        'outcome'   => 'success',
     1814                        'method'    => __METHOD__,
     1815                        'line'      => __LINE__,
     1816                        'data'      => array(
     1817                            'response' => $response_data
     1818                        )
     1819                    )
     1820                );
    13441821                // Payment successful
    13451822                $renewal_order->update_meta_data( '_convesiopay_payment_id', $payment_id );
     
    13541831            } else {
    13551832                $error_message = $response_data['message'] ?? $response_data['body']['message'] ?? 'Unknown error';
    1356                 peachpay_log( 'error', 'ConvesioPay: Stored-card renewal failed - HTTP ' . $response_code . ' - ' . $error_message . ' (order ' . $renewal_order->get_order_number() . ')' );
     1833                peachpay_log(
     1834                    'error',
     1835                    'ConvesioPay Card Subscription renewal failed - renewal order id - ' . $renewal_order->get_id(),
     1836                    array(
     1837                        'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     1838                        'component' => 'payments',
     1839                        'feature'   => 'convesiopay_gateway',
     1840                        'operation' => 'subscription.renewal',
     1841                        'outcome'   => 'failed',
     1842                        'line'      => __LINE__,
     1843                        'function'  => __FUNCTION__,
     1844                        'file'      => __FILE__,
     1845                        'class'     => __CLASS__,
     1846                        'method'    => __METHOD__,
     1847                        'data'      => array(
     1848                            'request_data' => $request_data,
     1849                            'response_data' => $response_data,
     1850                        ),
     1851                    )
     1852                );
    13571853                throw new Exception( 'Renewal payment failed: ' . $error_message );
    13581854            }
    13591855        } catch ( Exception $e ) {
    1360             peachpay_log( 'error', 'ConvesioPay: Stored-card renewal exception - ' . $e->getMessage() . ' (order ' . $renewal_order->get_order_number() . ')' );
    1361             $renewal_order->update_status( 'failed', sprintf(
    1362                 __( 'ConvesioPay renewal failed: %s', 'peachpay-for-woocommerce' ),
    1363                 $e->getMessage()
    1364             ) );
     1856            peachpay_log(
     1857                'error',
     1858                'ConvesioPay Card Subscription renewal failed - exception',
     1859                array(
     1860                    'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     1861                    'component' => 'payments',
     1862                    'feature'   => 'convesiopay_gateway',
     1863                    'operation' => 'subscription.renewal',
     1864                    'outcome'   => 'failed',
     1865                    'line'      => __LINE__,
     1866                    'function'  => __FUNCTION__,
     1867                    'file'      => __FILE__,
     1868                    'class'     => __CLASS__,
     1869                    'method'    => __METHOD__,
     1870                    'data'      => array(
     1871                        'message' => $e->getMessage(),
     1872                        'code' => $e->getCode(),
     1873                        'file' => $e->getFile(),
     1874                        'line' => $e->getLine(),
     1875                        'trace' => $e->getTraceAsString(),
     1876                    )
     1877                )
     1878            );
     1879
     1880            // Keep renewal order state consistent on failure for retries/reporting.
     1881            if ( $renewal_order instanceof WC_Order && ! $renewal_order->has_status( array( 'processing', 'completed' ) ) ) {
     1882                $failure_note = sprintf(
     1883                    /* translators: %s: failure message */
     1884                    __( 'ConvesioPay subscription renewal failed: %s', 'peachpay-for-woocommerce' ),
     1885                    $e->getMessage()
     1886                );
     1887                $renewal_order->update_status( 'failed', $failure_note );
     1888            }
    13651889        }
    13661890    }
  • peachpay-for-woocommerce/trunk/core/payments/convesiopay/gateways/class-peachpay-convesiopay-unified-gateway.php

    r3471281 r3490786  
    1717 */
    1818class PeachPay_ConvesioPay_Unified_Gateway extends PeachPay_Payment_Gateway {
     19    /**
     20     * Track whether the renewal hook has been registered.
     21     *
     22     * @var bool
     23     */
     24    private static $renewal_hook_registered = false;
     25
    1926    /**
    2027     * Track if gateway was properly initialized
     
    93100        add_action( 'admin_head', array( $this, 'hide_gateway_with_css' ) );
    94101       
    95         // Subscription renewal support - route to Card Gateway
    96         add_action(
    97             'woocommerce_scheduled_subscription_payment_' . $this->id,
    98             function ( $renewal_total, $renewal_order ) {
    99                 if ( ! function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ) {
    100                     return;
    101                 }
    102                 $gateways = WC()->payment_gateways->payment_gateways();
    103                 if ( isset( $gateways['peachpay_convesiopay_card'] ) ) {
    104                     $subscriptions = wcs_get_subscriptions_for_renewal_order( $renewal_order );
    105                     $subscription  = array_pop( $subscriptions );
    106                     if ( ! $subscription ) {
    107                         return;
    108                     }
    109                     $parent_order = wc_get_order( $subscription->get_parent_id() );
    110                     $gateways['peachpay_convesiopay_card']->process_subscription_renewal( $parent_order, $renewal_order, $renewal_total );
    111                 } else {
    112                     $renewal_order->update_status( 'failed', __( 'ConvesioPay Card gateway not found.', 'peachpay-for-woocommerce' ) );
    113                 }
    114             },
    115             10,
    116             2
    117         );
     102        // Subscription renewal support - route to Card Gateway.
     103        $this->register_subscription_renewal_hook();
    118104
    119105        // Hook into checkout update to read selected method from POST
     
    137123        // Mark as initialized
    138124        $this->initialized = true;
     125    }
     126
     127    /**
     128     * Register subscription renewal hook once per request.
     129     */
     130    private function register_subscription_renewal_hook() {
     131        if ( self::$renewal_hook_registered ) {
     132            return;
     133        }
     134        add_action(
     135            'woocommerce_scheduled_subscription_payment_' . $this->id,
     136            array( $this, 'handle_subscription_renewal_payment' ),
     137            10,
     138            2
     139        );
     140        self::$renewal_hook_registered = true;
     141    }
     142
     143    /**
     144     * Handle scheduled subscription payment for unified ConvesioPay gateway.
     145     *
     146     * @param float    $renewal_total Renewal amount.
     147     * @param WC_Order $renewal_order Renewal order.
     148     */
     149    public function handle_subscription_renewal_payment( $renewal_total, $renewal_order ) {
     150        if ( ! function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ) {
     151            peachpay_log(
     152                'error',
     153                'ConvesioPay Unified Subscription renewal failed - wcs_get_subscriptions_for_renewal_order() unavailable.',
     154                array(
     155                    'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     156                    'component' => 'payments',
     157                    'feature'   => 'convesiopay_gateway',
     158                    'operation' => 'subscription.renewal',
     159                    'outcome'   => 'failed',
     160                    'line'     => __LINE__,
     161                    'function' => __FUNCTION__,
     162                    'file'     => __FILE__,
     163                    'class'    => __CLASS__,
     164                    'method'   => __METHOD__,
     165                    'data'     => array(
     166                        'renewal_total' => $renewal_total,
     167                    ),
     168                )
     169            );
     170            return;
     171        }
     172
     173        $gateways = WC()->payment_gateways->payment_gateways();
     174        if ( ! isset( $gateways['peachpay_convesiopay_card'] ) ) {
     175            $renewal_order->update_status( 'failed', __( 'ConvesioPay Card gateway not found.', 'peachpay-for-woocommerce' ) );
     176            return;
     177        }
     178
     179        $subscriptions = wcs_get_subscriptions_for_renewal_order( $renewal_order );
     180        $subscription  = array_pop( $subscriptions );
     181        if ( ! $subscription ) {
     182            peachpay_log(
     183                'error',
     184                'ConvesioPay Unified Subscription renewal failed - no subscription found for renewal order.',
     185                array(
     186                    'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     187                    'component' => 'payments',
     188                    'feature'   => 'convesiopay_gateway',
     189                    'operation' => 'subscription.renewal',
     190                    'outcome'   => 'failed',
     191                    'line'     => __LINE__,
     192                    'function' => __FUNCTION__,
     193                    'file'     => __FILE__,
     194                    'class'    => __CLASS__,
     195                    'method'   => __METHOD__,
     196                    'data'     => array(
     197                        'renewal_total' => $renewal_total,
     198                    ),
     199                )
     200            );
     201            return;
     202        }
     203
     204        $parent_order = wc_get_order( $subscription->get_parent_id() );
     205        if ( ! $parent_order ) {
     206            peachpay_log(
     207                'error',
     208                'ConvesioPay Unified Subscription renewal failed - parent order not found.',
     209                array(
     210                    'event'     => 'payments.convesiopay_gateway.subscription.renewal.failed',
     211                    'component' => 'payments',
     212                    'feature'   => 'convesiopay_gateway',
     213                    'operation' => 'subscription.renewal',
     214                    'outcome'   => 'failed',
     215                    'line'     => __LINE__,
     216                    'function' => __FUNCTION__,
     217                    'file'     => __FILE__,
     218                    'class'    => __CLASS__,
     219                    'method'   => __METHOD__,
     220                )
     221            );
     222            return;
     223        }
     224
     225        peachpay_log(
     226            'debug',
     227            'ConvesioPay Unified Subscription renewal debug - delegating to card gateway.',
     228            array(
     229                'event'     => 'payments.convesiopay_gateway.subscription.renewal.debug',
     230                'component' => 'payments',
     231                'feature'   => 'convesiopay_gateway',
     232                'operation' => 'subscription.renewal',
     233                'outcome'   => 'debug',
     234                'line'     => __LINE__,
     235                'function' => __FUNCTION__,
     236                'file'     => __FILE__,
     237                'class'    => __CLASS__,
     238                'method'   => __METHOD__,
     239                'data'     => array(
     240                    'renewal_total' => $renewal_total,
     241                ),
     242            )
     243        );
     244        $gateways['peachpay_convesiopay_card']->process_subscription_renewal( $parent_order, $renewal_order, $renewal_total );
     245        peachpay_log(
     246            'debug',
     247            'ConvesioPay Unified Subscription renewal debug - card gateway delegation completed.',
     248            array(
     249                'event'     => 'payments.convesiopay_gateway.subscription.renewal.debug',
     250                'component' => 'payments',
     251                'feature'   => 'convesiopay_gateway',
     252                'operation' => 'subscription.renewal',
     253                'outcome'   => 'debug',
     254                'line'     => __LINE__,
     255                'function' => __FUNCTION__,
     256                'file'     => __FILE__,
     257                'class'    => __CLASS__,
     258                'method'   => __METHOD__,
     259            )
     260        );
    139261    }
    140262
     
    301423            WC()->session->set( 'convesiopay_selected_method', $selected_method );
    302424            if ( $previous_method !== $selected_method ) {
    303                 peachpay_log( 'debug', 'ConvesioPay: Unified checkout synced selected method on checkout_process => ' . $selected_method );
     425                peachpay_log(
     426                    'debug',
     427                    'Payments: Checkout method sync debug.',
     428                    array(
     429                        'event'     => 'payments.convesiopay_gateway.checkout.method_sync.debug',
     430                        'component' => 'payments',
     431                        'feature'   => 'convesiopay_gateway',
     432                        'operation' => 'checkout.method_sync',
     433                        'outcome'   => 'debug',
     434                        'method'    => __METHOD__,
     435                        'line'      => __LINE__,
     436                        'data'      => array(
     437                            'selected_method' => $selected_method,
     438                            'previous_method' => $previous_method,
     439                        ),
     440                    )
     441                );
    304442            }
    305443        }
     
    632770           
    633771        } catch ( Exception $e ) {
    634             peachpay_log( 'error', 'ConvesioPay: Unified payment processing failed - ' . $e->getMessage() . ' (order ' . ( $order ? $order->get_order_number() : $order_id ) . ')' );
     772            peachpay_log(
     773                'error',
     774                'Payments: Unified process payment failed.',
     775                array(
     776                    'event'     => 'payments.convesiopay_gateway.process_payment.failed',
     777                    'component' => 'payments',
     778                    'feature'   => 'convesiopay_gateway',
     779                    'operation' => 'process_payment',
     780                    'outcome'   => 'failed',
     781                    'method'    => __METHOD__,
     782                    'line'      => __LINE__,
     783                    'data'      => array(
     784                        'order_id' => $order_id,
     785                        'order_number' => ( $order && is_a( $order, 'WC_Order' ) ) ? $order->get_order_number() : $order_id,
     786                        'error_message' => $e->getMessage(),
     787                    ),
     788                )
     789            );
    635790            return array(
    636791                'result'   => 'failure',
     
    10661221        $status = $payment_data['status'];
    10671222
    1068         peachpay_log( 'info', 'ConvesioPay: Generic payment received - order ' . $order->get_order_number() . ', payment_id ' . $payment_id . ', method ' . $payment_method . ', status ' . $status );
     1223        peachpay_log(
     1224            'info',
     1225            'Payments: Generic payment received.',
     1226            array(
     1227                'event'     => 'payments.convesiopay_gateway.generic_payment.received',
     1228                'component' => 'payments',
     1229                'feature'   => 'convesiopay_gateway',
     1230                'operation' => 'generic_payment.received',
     1231                'outcome'   => 'success',
     1232                'method'    => __METHOD__,
     1233                'line'      => __LINE__,
     1234                'data'      => array(
     1235                    'order_id' => $order->get_id(),
     1236                    'order_number' => $order->get_order_number(),
     1237                    'payment_id' => $payment_id,
     1238                    'payment_method' => $payment_method,
     1239                    'status' => $status,
     1240                ),
     1241            )
     1242        );
    10691243
    10701244        // Set order transaction ID
     
    10911265        $order->save();
    10921266
    1093         peachpay_log( 'info', 'ConvesioPay: Generic payment completed - order ' . $order->get_order_number() . ', payment_id ' . $payment_id );
     1267        peachpay_log(
     1268            'info',
     1269            'Payments: Generic payment completed.',
     1270            array(
     1271                'event'     => 'payments.convesiopay_gateway.generic_payment.completed',
     1272                'component' => 'payments',
     1273                'feature'   => 'convesiopay_gateway',
     1274                'operation' => 'generic_payment.completed',
     1275                'outcome'   => 'success',
     1276                'method'    => __METHOD__,
     1277                'line'      => __LINE__,
     1278                'data'      => array(
     1279                    'order_id' => $order->get_id(),
     1280                    'order_number' => $order->get_order_number(),
     1281                    'payment_id' => $payment_id,
     1282                    'payment_method' => $payment_method,
     1283                    'status' => $status,
     1284                ),
     1285            )
     1286        );
    10941287        return array(
    10951288            'result'   => 'success',
     
    13121505
    13131506            if ( ! $payment_id ) {
    1314                 peachpay_log( 'error', 'ConvesioPay: Refund - payment ID not found for order ' . $order->get_order_number() );
     1507                peachpay_log(
     1508                    'error',
     1509                    'Payments: Refund failed.',
     1510                    array(
     1511                        'event'     => 'payments.convesiopay_gateway.refund.failed',
     1512                        'component' => 'payments',
     1513                        'feature'   => 'convesiopay_gateway',
     1514                        'operation' => 'refund',
     1515                        'outcome'   => 'failed',
     1516                        'method'    => __METHOD__,
     1517                        'line'      => __LINE__,
     1518                        'data'      => array(
     1519                            'details' => 'ConvesioPay: Refund - payment ID not found for order ' . $order->get_order_number()
     1520                )));
    13151521                return new WP_Error( 'convesiopay_refund_error', __( 'Payment ID not found for this order.', 'peachpay-for-woocommerce' ) );
    13161522            }
     
    13341540            // Build refund endpoint URL
    13351541            $refund_endpoint = $config['api_url'] . '/payments/' . $payment_id . '/refund';
    1336             peachpay_log( 'debug', 'ConvesioPay: Refund API request for order ' . $order->get_order_number() . ', payment ' . $payment_id . ', amount ' . $refund_data['amount'] . ' ' . $refund_data['currency'] );
     1542            peachpay_log(
     1543                'debug',
     1544                'Payments: Refund debug.',
     1545                array(
     1546                    'event'     => 'payments.convesiopay_gateway.refund.debug',
     1547                    'component' => 'payments',
     1548                    'feature'   => 'convesiopay_gateway',
     1549                    'operation' => 'refund',
     1550                    'outcome'   => 'debug',
     1551                    'method'    => __METHOD__,
     1552                    'line'      => __LINE__,
     1553                    'data'      => array(
     1554                        'details' => 'ConvesioPay: Refund API request for order ' . $order->get_order_number() . ', payment ' . $payment_id . ', amount ' . $refund_data['amount'] . ' ' . $refund_data['currency']
     1555            )));
    13371556
    13381557            // Add order note for refund request
     
    13561575
    13571576            if ( is_wp_error( $response ) ) {
    1358                 peachpay_log( 'error', 'ConvesioPay: Refund network error - ' . $response->get_error_message() . ' (order ' . $order->get_order_number() . ', payment ' . $payment_id . ')' );
     1577                peachpay_log(
     1578                    'error',
     1579                    'Payments: Refund failed.',
     1580                    array(
     1581                        'event'     => 'payments.convesiopay_gateway.refund.failed',
     1582                        'component' => 'payments',
     1583                        'feature'   => 'convesiopay_gateway',
     1584                        'operation' => 'refund',
     1585                        'outcome'   => 'failed',
     1586                        'method'    => __METHOD__,
     1587                        'line'      => __LINE__,
     1588                        'data'      => array(
     1589                            'details' => 'ConvesioPay: Refund network error - ' . $response->get_error_message() . ' (order ' . $order->get_order_number() . ', payment ' . $payment_id . ')'
     1590                )));
    13591591                $order->add_order_note( sprintf(
    13601592                    __( 'ConvesioPay refund response: Network error - %s', 'peachpay-for-woocommerce' ),
     
    13701602            if ( $response_code !== 200 ) {
    13711603                $error_message = isset( $response_data['message'] ) ? $response_data['message'] : 'Refund failed (HTTP ' . $response_code . ')';
    1372                 peachpay_log( 'error', 'ConvesioPay: Refund API error - ' . $error_message . ' (order ' . $order->get_order_number() . ', payment ' . $payment_id . ')' );
     1604                peachpay_log(
     1605                    'error',
     1606                    'Payments: Refund failed.',
     1607                    array(
     1608                        'event'     => 'payments.convesiopay_gateway.refund.failed',
     1609                        'component' => 'payments',
     1610                        'feature'   => 'convesiopay_gateway',
     1611                        'operation' => 'refund',
     1612                        'outcome'   => 'failed',
     1613                        'method'    => __METHOD__,
     1614                        'line'      => __LINE__,
     1615                        'data'      => array(
     1616                            'details' => 'ConvesioPay: Refund API error - ' . $error_message . ' (order ' . $order->get_order_number() . ', payment ' . $payment_id . ')'
     1617                )));
    13731618                return new WP_Error( 'convesiopay_refund_error', $error_message );
    13741619            }
     
    13761621            // Refund successful - extract refund details from response
    13771622            $refund_id = isset( $response_data['id'] ) ? $response_data['id'] : '';
    1378             peachpay_log( 'info', 'ConvesioPay: Refund success - order ' . $order->get_order_number() . ', refund_id ' . $refund_id );
     1623            peachpay_log(
     1624                'info',
     1625                'Payments: Refund success.',
     1626                array(
     1627                    'event'     => 'payments.convesiopay_gateway.refund.success',
     1628                    'component' => 'payments',
     1629                    'feature'   => 'convesiopay_gateway',
     1630                    'operation' => 'refund',
     1631                    'outcome'   => 'success',
     1632                    'method'    => __METHOD__,
     1633                    'line'      => __LINE__,
     1634                    'data'      => array(
     1635                        'details' => 'ConvesioPay: Refund success - order ' . $order->get_order_number() . ', refund_id ' . $refund_id
     1636            )));
    13791637
    13801638            // Add detailed order note
     
    14131671
    14141672        } catch ( Exception $e ) {
    1415             peachpay_log( 'error', 'ConvesioPay: Refund exception - ' . $e->getMessage() . ' (order ' . $order->get_order_number() . ')' );
     1673            peachpay_log(
     1674                'error',
     1675                'Payments: Refund failed.',
     1676                array(
     1677                    'event'     => 'payments.convesiopay_gateway.refund.failed',
     1678                    'component' => 'payments',
     1679                    'feature'   => 'convesiopay_gateway',
     1680                    'operation' => 'refund',
     1681                    'outcome'   => 'failed',
     1682                    'method'    => __METHOD__,
     1683                    'line'      => __LINE__,
     1684                    'data'      => array(
     1685                        'details' => 'ConvesioPay: Refund exception - ' . $e->getMessage() . ' (order ' . $order->get_order_number() . ')'
     1686            )));
    14161687            return new WP_Error( 'convesiopay_refund_error', $e->getMessage() );
    14171688        }
     
    14261697     */
    14271698    private function find_payment_by_order_number( $order_number, $config ) {
    1428         peachpay_log( 'debug', 'ConvesioPay: GET /payments/list API request for order_number ' . $order_number );
     1699        peachpay_log(
     1700            'debug',
     1701            'Payments: Find payment by order number debug.',
     1702            array(
     1703                'event'     => 'payments.convesiopay_gateway.find_payment_by_order_number.debug',
     1704                'component' => 'payments',
     1705                'feature'   => 'convesiopay_gateway',
     1706                'operation' => 'find_payment_by_order_number',
     1707                'outcome'   => 'debug',
     1708                'method'    => __METHOD__,
     1709                'line'      => __LINE__,
     1710                'data'      => array(
     1711                    'order_number' => $order_number,
     1712                    'api_url' => $config['api_url'] . '/payments/list',
     1713                ),
     1714            )
     1715        );
    14291716
    14301717        // Make API call to ConvesioPay to find payment by order number
     
    14381725
    14391726        if ( is_wp_error( $response ) ) {
    1440             peachpay_log( 'error', 'ConvesioPay: GET /payments/list network error - ' . $response->get_error_message() . ' (order_number ' . $order_number . ')' );
     1727            peachpay_log(
     1728                'error',
     1729                'Payments: Find payment by order number failed.',
     1730                array(
     1731                    'event'     => 'payments.convesiopay_gateway.find_payment_by_order_number.failed',
     1732                    'component' => 'payments',
     1733                    'feature'   => 'convesiopay_gateway',
     1734                    'operation' => 'find_payment_by_order_number',
     1735                    'outcome'   => 'failed',
     1736                    'method'    => __METHOD__,
     1737                    'line'      => __LINE__,
     1738                    'data'      => array(
     1739                        'order_number' => $order_number,
     1740                        'error_message' => $response->get_error_message(),
     1741                    ),
     1742                )
     1743            );
    14411744            return false;
    14421745        }
     
    14471750
    14481751        if ( $response_code !== 200 || empty( $response_data['payments'] ) ) {
    1449             peachpay_log( 'warning', 'ConvesioPay: GET /payments/list - HTTP ' . $response_code . ' or no payments (order_number ' . $order_number . ')' );
     1752            peachpay_log(
     1753                'warning',
     1754                'Payments: Find payment by order number warning.',
     1755                array(
     1756                    'event'     => 'payments.convesiopay_gateway.find_payment_by_order_number.warning',
     1757                    'component' => 'payments',
     1758                    'feature'   => 'convesiopay_gateway',
     1759                    'operation' => 'find_payment_by_order_number',
     1760                    'outcome'   => 'warning',
     1761                    'method'    => __METHOD__,
     1762                    'line'      => __LINE__,
     1763                    'data'      => array(
     1764                        'order_number' => $order_number,
     1765                        'response_code' => $response_code,
     1766                        'payments_count' => isset( $response_data['payments'] ) && is_array( $response_data['payments'] ) ? count( $response_data['payments'] ) : 0,
     1767                    ),
     1768                )
     1769            );
    14501770            return false;
    14511771        }
     
    14531773        $payment_id = $response_data['payments'][0]['id'] ?? false;
    14541774        if ( $payment_id ) {
    1455             peachpay_log( 'info', 'ConvesioPay: GET /payments/list found payment ' . $payment_id . ' for order_number ' . $order_number );
     1775            peachpay_log(
     1776                'info',
     1777                'Payments: Find payment by order number success.',
     1778                array(
     1779                    'event'     => 'payments.convesiopay_gateway.find_payment_by_order_number.success',
     1780                    'component' => 'payments',
     1781                    'feature'   => 'convesiopay_gateway',
     1782                    'operation' => 'find_payment_by_order_number',
     1783                    'outcome'   => 'success',
     1784                    'method'    => __METHOD__,
     1785                    'line'      => __LINE__,
     1786                    'data'      => array(
     1787                        'order_number' => $order_number,
     1788                        'payment_id' => $payment_id,
     1789                    ),
     1790                )
     1791            );
    14561792        }
    14571793        return $payment_id;
  • peachpay-for-woocommerce/trunk/core/payments/convesiopay/routes/class-peachpay-convesiopay-reconciliation.php

    r3460037 r3490786  
    124124            }
    125125
    126             peachpay_log( 'info', 'PeachPay Reconciliation: Cron started' );
     126            peachpay_log(
     127                'info',
     128                'ConvesioPay Reconciliation cron callback - started.',
     129                array(
     130                    'event'     => 'payments.convesiopay_reconciliation.cron_callback.started',
     131                    'component' => 'payments',
     132                    'feature'   => 'convesiopay_reconciliation',
     133                    'operation' => 'cron_callback',
     134                    'outcome'   => 'started',
     135                    'method'    => __METHOD__,
     136                    'line'      => __LINE__,
     137                )
     138            );
    127139
    128140            // Get eligible orders for reconciliation
     
    131143            $order_ids = array( 0 );
    132144            if ( empty( $orders ) ) {
    133                 peachpay_log( 'info', 'PeachPay Reconciliation: Cron finished (no eligible orders)' );
     145                peachpay_log(
     146                    'info',
     147                    'ConvesioPay Reconciliation cron callback - no eligible orders.',
     148                    array(
     149                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     150                        'component' => 'payments',
     151                        'feature'   => 'convesiopay_reconciliation',
     152                        'operation' => 'reconciliation',
     153                        'outcome'   => 'success',
     154                        'method'    => __METHOD__,
     155                        'line'      => __LINE__,
     156                    )
     157                );
    134158                return;
    135159            }
     
    147171                        $order->update_status( 'failed', 'ConvesioPay reconciliation failed after multiple attempts.' );
    148172                        $order->save();
    149                         peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order->get_id() . ' marked failed (max attempts in loop)' );
     173                        peachpay_log(
     174                            'info',
     175                            'ConvesioPay Reconciliation order processing - max attempts reached.',
     176                            array(
     177                                'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     178                                'component' => 'payments',
     179                                'feature'   => 'convesiopay_reconciliation',
     180                                'operation' => 'reconciliation',
     181                                'outcome'   => 'success',
     182                                'method'    => __METHOD__,
     183                                'line'      => __LINE__,
     184                                'data'      => array(
     185                                    'details' => 'PeachPay Reconciliation: Order #' . $order->get_id() . ' marked failed (max attempts in loop)'
     186                        )));
    150187                        continue;
    151188                    }
     
    158195            }
    159196
    160             peachpay_log( 'info', 'PeachPay Reconciliation: Cron finished for orders: ' . implode(', ', $order_ids) );
     197            peachpay_log(
     198                'info',
     199                'ConvesioPay Reconciliation cron callback - completed.',
     200                array(
     201                    'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     202                    'component' => 'payments',
     203                    'feature'   => 'convesiopay_reconciliation',
     204                    'operation' => 'reconciliation',
     205                    'outcome'   => 'success',
     206                    'method'    => __METHOD__,
     207                    'line'      => __LINE__,
     208                    'data'      => array(
     209                        'details' => 'PeachPay Reconciliation: Cron finished for orders: ' . implode(', ', $order_ids)
     210            )));
    161211        } catch ( \Throwable $e ) {
    162212            $this->log_reconciliation_error( 'run_reconciliation', $e );
     
    217267
    218268            $count = count( $orders );
    219             peachpay_log( 'info', 'PeachPay Reconciliation: ' . $count . ' eligible orders' );
     269            peachpay_log(
     270                'info',
     271                'ConvesioPay Reconciliation eligible orders fetch - completed.',
     272                array(
     273                    'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     274                    'component' => 'payments',
     275                    'feature'   => 'convesiopay_reconciliation',
     276                    'operation' => 'reconciliation',
     277                    'outcome'   => 'success',
     278                    'method'    => __METHOD__,
     279                    'line'      => __LINE__,
     280                    'data'      => array(
     281                        'details' => 'PeachPay Reconciliation: ' . $count . ' eligible orders'
     282            )));
    220283            return array_values( $orders );
    221284        } catch ( \Throwable $e ) {
     
    237300        try {
    238301            if ( get_transient( $lock_key ) ) {
    239                 peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order_id . ' already being processed by another cron run' );
     302                peachpay_log(
     303                    'info',
     304                    'ConvesioPay Reconciliation order processing - skipped (already locked).',
     305                    array(
     306                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     307                        'component' => 'payments',
     308                        'feature'   => 'convesiopay_reconciliation',
     309                        'operation' => 'reconciliation',
     310                        'outcome'   => 'success',
     311                        'method'    => __METHOD__,
     312                        'line'      => __LINE__,
     313                        'data'      => array(
     314                            'details' => 'PeachPay Reconciliation: Order #' . $order_id . ' already being processed by another cron run'
     315                )));
    240316                return;
    241317            }
     
    243319            set_transient( $lock_key, 1, PEACHPAY_CONVESIOPAY_RECONCILE_LOCK_TTL );
    244320
    245             peachpay_log( 'info', 'PeachPay Reconciliation: Processing order #' . $order_id );
     321            peachpay_log(
     322                'info',
     323                'ConvesioPay Reconciliation order processing - started for order #' . $order_id,
     324                array(
     325                    'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     326                    'component' => 'payments',
     327                    'feature'   => 'convesiopay_reconciliation',
     328                    'operation' => 'reconciliation',
     329                    'outcome'   => 'success',
     330                    'method'    => __METHOD__,
     331                    'line'      => __LINE__,
     332                    'data'      => array(
     333                        'details' => 'PeachPay Reconciliation: Processing order #' . $order_id
     334            )));
    246335
    247336            $order = wc_get_order( $order_id );
     
    249338            if ( ! $order || ! $order->has_status( 'pending' ) ) {
    250339                delete_transient( $lock_key );
    251                 peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order_id . ' no longer pending' );
     340                peachpay_log(
     341                    'info',
     342                    'ConvesioPay Reconciliation order processing - skipped (order not pending) , order #' . $order_id,
     343                    array(
     344                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     345                        'component' => 'payments',
     346                        'feature'   => 'convesiopay_reconciliation',
     347                        'operation' => 'reconciliation',
     348                        'outcome'   => 'success',
     349                        'method'    => __METHOD__,
     350                        'line'      => __LINE__,
     351                        'data'      => array(
     352                            'details' => 'PeachPay Reconciliation: Order #' . $order_id . ' no longer pending'
     353                )));
    252354                return;
    253355            }
     
    261363                $this->increment_reconcile_attempt_and_maybe_fail( $order );
    262364                delete_transient($lock_key);
    263                 peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order_id . ' no payment ID (' . $debug . ')' );
     365                peachpay_log(
     366                    'info',
     367                    'ConvesioPay Reconciliation order processing - skipped (missing payment ID) , order #' . $order_id,
     368                    array(
     369                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     370                        'component' => 'payments',
     371                        'feature'   => 'convesiopay_reconciliation',
     372                        'operation' => 'reconciliation',
     373                        'outcome'   => 'success',
     374                        'method'    => __METHOD__,
     375                        'line'      => __LINE__,
     376                        'data'      => array(
     377                            'details' => 'PeachPay Reconciliation: Order #' . $order_id . ' no payment ID (' . $debug . ')'
     378                )));
    264379                return;
    265380            }
     
    274389            if ($poll_result === false) {
    275390                $this->increment_reconcile_attempt_and_maybe_fail( $order );
    276                 peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order_id . ' poll result false' );
     391                peachpay_log(
     392                    'info',
     393                    'ConvesioPay Reconciliation order processing - poll failed, order #' . $order_id,
     394                    array(
     395                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     396                        'component' => 'payments',
     397                        'feature'   => 'convesiopay_reconciliation',
     398                        'operation' => 'reconciliation',
     399                        'outcome'   => 'success',
     400                        'method'    => __METHOD__,
     401                        'line'      => __LINE__,
     402                        'data'      => array(
     403                            'details' => 'PeachPay Reconciliation: Order #' . $order_id . ' poll result false'
     404                )));
    277405                return;
    278406            }
     
    298426                $order->update_meta_data('_convesiopay_reconcile_last_poll_at', time());
    299427                $order->save();
    300                 peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order_id . ' still pending (status: ' . $status . '), will retry' );
     428                peachpay_log(
     429                    'info',
     430                    'ConvesioPay Reconciliation order processing - pending retry, order #' . $order_id,
     431                    array(
     432                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     433                        'component' => 'payments',
     434                        'feature'   => 'convesiopay_reconciliation',
     435                        'operation' => 'reconciliation',
     436                        'outcome'   => 'success',
     437                        'method'    => __METHOD__,
     438                        'line'      => __LINE__,
     439                        'data'      => array(
     440                            'details' => 'PeachPay Reconciliation: Order #' . $order_id . ' still pending (status: ' . $status . '), will retry'
     441                )));
    301442            }
    302443        } catch ( \Throwable $e ) {
     
    317458        if ( $attempts >= PEACHPAY_CONVESIOPAY_RECONCILE_MAX_ATTEMPTS ) {
    318459            $order->update_status( 'failed', 'ConvesioPay reconciliation failed after multiple attempts.' );
    319             peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order->get_id() . ' marked failed (max attempts reached)' );
     460            peachpay_log(
     461                'info',
     462                'ConvesioPay Reconciliation retry attempts - max reached.',
     463                array(
     464                    'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     465                    'component' => 'payments',
     466                    'feature'   => 'convesiopay_reconciliation',
     467                    'operation' => 'reconciliation',
     468                    'outcome'   => 'success',
     469                    'method'    => __METHOD__,
     470                    'line'      => __LINE__,
     471                    'data'      => array(
     472                        'details' => 'PeachPay Reconciliation: Order #' . $order->get_id() . ' marked failed (max attempts reached)'
     473            )));
    320474        }
    321475        $order->save();
     
    366520            // Check if the API request failed
    367521            if (is_wp_error($response)) {
    368                 peachpay_log( 'error', 'PeachPay Reconciliation: GET payment failed - ' . $response->get_error_message() );
     522                peachpay_log(
     523                    'error',
     524                    'ConvesioPay Reconciliation fetch payment status - failed.',
     525                    array(
     526                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.failed',
     527                        'component' => 'payments',
     528                        'feature'   => 'convesiopay_reconciliation',
     529                        'operation' => 'reconciliation',
     530                        'outcome'   => 'failed',
     531                        'method'    => __METHOD__,
     532                        'line'      => __LINE__,
     533                        'data'      => array(
     534                            'details' => 'PeachPay Reconciliation: GET payment failed - ' . $response->get_error_message()
     535                )));
    369536                return false;
    370537            }
     
    373540
    374541            if ( $code !== 200 ) {
    375                 peachpay_log( 'error', 'PeachPay Reconciliation: GET payment HTTP ' . $code . ' for payment ' . $payment_id . ' - ' . $body );
     542                peachpay_log(
     543                    'error',
     544                    'ConvesioPay Reconciliation fetch payment status - failed.',
     545                    array(
     546                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.failed',
     547                        'component' => 'payments',
     548                        'feature'   => 'convesiopay_reconciliation',
     549                        'operation' => 'reconciliation',
     550                        'outcome'   => 'failed',
     551                        'method'    => __METHOD__,
     552                        'line'      => __LINE__,
     553                        'data'      => array(
     554                            'details' => 'PeachPay Reconciliation: GET payment HTTP ' . $code . ' for payment ' . $payment_id . ' - ' . $body
     555                )));
    376556                return false;
    377557            }
    378558
    379             peachpay_log( 'debug', 'PeachPay CPay API: GET /payments/' . $payment_id . ' - HTTP ' . $code . ' - ' . $body );
     559            peachpay_log(
     560                'debug',
     561                'ConvesioPay Reconciliation fetch payment status - debug.',
     562                array(
     563                    'event'     => 'payments.convesiopay_reconciliation.fetch_payment_status.debug',
     564                    'component' => 'payments',
     565                    'feature'   => 'convesiopay_reconciliation',
     566                    'operation' => 'fetch_payment_status',
     567                    'outcome'   => 'debug',
     568                    'method'    => __METHOD__,
     569                    'line'      => __LINE__,
     570                    'data'      => array(
     571                        'details' => 'PeachPay CPay API: GET /payments/' . $payment_id . ' - HTTP ' . $code . ' - ' . $body
     572            )));
    380573
    381574            // Decode the response body
     
    384577            // Check if the response body is not valid JSON or does not have a status
    385578            if (! is_array($data) || empty($data['status'])) {
    386                 peachpay_log( 'error', 'PeachPay Reconciliation: GET payment invalid response for ' . $payment_id . ' - missing status or invalid JSON' );
     579                peachpay_log(
     580                    'error',
     581                    'ConvesioPay Reconciliation fetch payment status - invalid response.',
     582                    array(
     583                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.failed',
     584                        'component' => 'payments',
     585                        'feature'   => 'convesiopay_reconciliation',
     586                        'operation' => 'reconciliation',
     587                        'outcome'   => 'failed',
     588                        'method'    => __METHOD__,
     589                        'line'      => __LINE__,
     590                        'data'      => array(
     591                            'details' => 'PeachPay Reconciliation: GET payment invalid response for ' . $payment_id . ' - missing status or invalid JSON'
     592                )));
    387593                return false;
    388594            }
     
    412618
    413619            if ( empty( $api_url ) || empty( $secret ) ) {
    414                 peachpay_log( 'error', 'PeachPay Reconciliation: List payments skipped - missing api_url or secret_key' );
     620                peachpay_log(
     621                    'error',
     622                    'ConvesioPay Reconciliation list payments fetch - config missing.',
     623                    array(
     624                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.failed',
     625                        'component' => 'payments',
     626                        'feature'   => 'convesiopay_reconciliation',
     627                        'operation' => 'reconciliation',
     628                        'outcome'   => 'failed',
     629                        'method'    => __METHOD__,
     630                        'line'      => __LINE__,
     631                    )
     632                );
    415633                return $map;
    416634            }
     
    471689
    472690                if ( is_wp_error( $response ) ) {
    473                     peachpay_log( 'error', 'PeachPay Reconciliation: List payments failed - ' . $response->get_error_message() );
     691                    peachpay_log(
     692                        'error',
     693                        'ConvesioPay Reconciliation list payments fetch - failed.',
     694                        array(
     695                            'event'     => 'payments.convesiopay_reconciliation.reconciliation.failed',
     696                            'component' => 'payments',
     697                            'feature'   => 'convesiopay_reconciliation',
     698                            'operation' => 'reconciliation',
     699                            'outcome'   => 'failed',
     700                            'method'    => __METHOD__,
     701                            'line'      => __LINE__,
     702                            'data'      => array(
     703                                'details' => 'PeachPay Reconciliation: List payments failed - ' . $response->get_error_message()
     704                    )));
    474705                    break;
    475706                }
     
    478709                if ( $code !== 200 ) {
    479710                    $body = wp_remote_retrieve_body( $response );
    480                     peachpay_log( 'error', 'PeachPay Reconciliation: List payments HTTP ' . $code . ' - ' . $body );
     711                    peachpay_log(
     712                        'error',
     713                        'ConvesioPay Reconciliation list payments fetch - failed.',
     714                        array(
     715                            'event'     => 'payments.convesiopay_reconciliation.reconciliation.failed',
     716                            'component' => 'payments',
     717                            'feature'   => 'convesiopay_reconciliation',
     718                            'operation' => 'reconciliation',
     719                            'outcome'   => 'failed',
     720                            'method'    => __METHOD__,
     721                            'line'      => __LINE__,
     722                            'data'      => array(
     723                                'details' => 'PeachPay Reconciliation: List payments HTTP ' . $code . ' - ' . $body
     724                    )));
    481725                    break;
    482726                }
     
    501745            } while ( $page <= $pages );
    502746
    503             peachpay_log( 'debug', 'PeachPay Reconciliation: List API returned ' . count( $map ) . ' payments' );
     747            peachpay_log(
     748                'debug',
     749                'ConvesioPay Reconciliation list payments fetch - debug.',
     750                array(
     751                    'event'     => 'payments.convesiopay_reconciliation.reconciliation.debug',
     752                    'component' => 'payments',
     753                    'feature'   => 'convesiopay_reconciliation',
     754                    'operation' => 'reconciliation',
     755                    'outcome'   => 'debug',
     756                    'method'    => __METHOD__,
     757                    'line'      => __LINE__,
     758                    'data'      => array(
     759                        'details' => 'PeachPay Reconciliation: List API returned ' . count( $map ) . ' payments'
     760            )));
    504761
    505762        } catch ( \Throwable $e ) {
     
    546803                case 'cancelled':  // ConvesioPay documentation status
    547804                    $this->handle_payment_cancelled( $order, $payment_id );
    548                     peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order_id . ' → Cancelled' );
     805                    peachpay_log(
     806                        'info',
     807                        'ConvesioPay Reconciliation status apply - cancelled handled.',
     808                        array(
     809                            'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     810                            'component' => 'payments',
     811                            'feature'   => 'convesiopay_reconciliation',
     812                            'operation' => 'reconciliation',
     813                            'outcome'   => 'success',
     814                            'method'    => __METHOD__,
     815                            'line'      => __LINE__,
     816                            'data'      => array(
     817                                'details' => 'PeachPay Reconciliation: Order #' . $order_id . ' → Cancelled'
     818                    )));
    549819                    break;
    550820
     
    553823                case 'disputed':   // ConvesioPay documentation status
    554824                    $this->handle_payment_failure( $order, $payment_id, $payment_data );
    555                     peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order_id . ' → Failed (' . $status . ')' );
     825                    peachpay_log(
     826                        'info',
     827                        'ConvesioPay Reconciliation status apply - failure handled.',
     828                        array(
     829                            'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     830                            'component' => 'payments',
     831                            'feature'   => 'convesiopay_reconciliation',
     832                            'operation' => 'reconciliation',
     833                            'outcome'   => 'success',
     834                            'method'    => __METHOD__,
     835                            'line'      => __LINE__,
     836                            'data'      => array(
     837                                'details' => 'PeachPay Reconciliation: Order #' . $order_id . ' → Failed (' . $status . ')'
     838                    )));
    556839                    break;
    557840
    558841                case 'refunded':   // ConvesioPay documentation status - handle as refund
    559842                    $this->handle_payment_refund( $order, $payment_id, $payment_data );
    560                     peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order_id . ' → Refunded' );
     843                    peachpay_log(
     844                        'info',
     845                        'ConvesioPay Reconciliation status apply - refund handled.',
     846                        array(
     847                            'event'     => 'payments.convesiopay_reconciliation.refund.success',
     848                            'component' => 'payments',
     849                            'feature'   => 'convesiopay_reconciliation',
     850                            'operation' => 'refund',
     851                            'outcome'   => 'success',
     852                            'method'    => __METHOD__,
     853                            'line'      => __LINE__,
     854                            'data'      => array(
     855                                'details' => 'PeachPay Reconciliation: Order #' . $order_id . ' → Refunded'
     856                    )));
    561857                    break;
    562858
     
    584880        // Check if order is already completed or refunded
    585881        if ($order->has_status(array('processing', 'completed', 'refunded'))) {
    586             peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order->get_id() . ' already completed or refunded' );
     882            peachpay_log(
     883                'info',
     884                'ConvesioPay Reconciliation payment success handler - skipped (already processed).',
     885                array(
     886                    'event'     => 'payments.convesiopay_reconciliation.refund.success',
     887                    'component' => 'payments',
     888                    'feature'   => 'convesiopay_reconciliation',
     889                    'operation' => 'refund',
     890                    'outcome'   => 'success',
     891                    'method'    => __METHOD__,
     892                    'line'      => __LINE__,
     893                    'data'      => array(
     894                        'details' => 'PeachPay Reconciliation: Order #' . $order->get_id() . ' already completed or refunded'
     895            )));
    587896            return;
    588897        }
     
    672981       
    673982        $order->save();
    674         peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment success' );
     983        peachpay_log(
     984            'info',
     985            'ConvesioPay Reconciliation payment success handler - completed.',
     986            array(
     987                'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     988                'component' => 'payments',
     989                'feature'   => 'convesiopay_reconciliation',
     990                'operation' => 'reconciliation',
     991                'outcome'   => 'success',
     992                'method'    => __METHOD__,
     993                'line'      => __LINE__,
     994                'data'      => array(
     995                    'details' => 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment success'
     996        )));
    675997    }
    676998
     
    7051027            $order->save();
    7061028
    707             peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment cancelled' );
     1029            peachpay_log(
     1030                'info',
     1031                'ConvesioPay Reconciliation payment cancellation handler - note added.',
     1032                array(
     1033                    'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     1034                    'component' => 'payments',
     1035                    'feature'   => 'convesiopay_reconciliation',
     1036                    'operation' => 'reconciliation',
     1037                    'outcome'   => 'success',
     1038                    'method'    => __METHOD__,
     1039                    'line'      => __LINE__,
     1040                    'data'      => array(
     1041                        'details' => 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment cancelled'
     1042            )));
    7081043            return;
    7091044        }
     
    7331068
    7341069        $order->save();
    735         peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment cancelled' );
     1070        peachpay_log(
     1071            'info',
     1072            'ConvesioPay Reconciliation payment cancellation handler - completed.',
     1073            array(
     1074                'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     1075                'component' => 'payments',
     1076                'feature'   => 'convesiopay_reconciliation',
     1077                'operation' => 'reconciliation',
     1078                'outcome'   => 'success',
     1079                'method'    => __METHOD__,
     1080                'line'      => __LINE__,
     1081                'data'      => array(
     1082                    'details' => 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment cancelled'
     1083        )));
    7361084    }
    7371085
     
    7671115            $order->add_order_note( $note . ' (Ignored - order already processed)' );
    7681116            $order->save();
    769             peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment failure (Ignored - order already processed)' );
     1117            peachpay_log(
     1118                'info',
     1119                'ConvesioPay Reconciliation payment failure handler - ignored.',
     1120                array(
     1121                    'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     1122                    'component' => 'payments',
     1123                    'feature'   => 'convesiopay_reconciliation',
     1124                    'operation' => 'reconciliation',
     1125                    'outcome'   => 'success',
     1126                    'method'    => __METHOD__,
     1127                    'line'      => __LINE__,
     1128                    'data'      => array(
     1129                        'details' => 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment failure (Ignored - order already processed)'
     1130            )));
    7701131            return;
    7711132        }
     
    7761137        $order->save();
    7771138
    778         peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment failure' );
     1139        peachpay_log(
     1140            'info',
     1141            'ConvesioPay Reconciliation payment failure handler - completed.',
     1142            array(
     1143                'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     1144                'component' => 'payments',
     1145                'feature'   => 'convesiopay_reconciliation',
     1146                'operation' => 'reconciliation',
     1147                'outcome'   => 'success',
     1148                'method'    => __METHOD__,
     1149                'line'      => __LINE__,
     1150                'data'      => array(
     1151                    'details' => 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment failure'
     1152        )));
    7791153    }
    7801154
     
    8971271
    8981272            if ( ! $order ) {
    899                 peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order_id . ' handled payment refund (order not found after refresh)' );
     1273                peachpay_log(
     1274                    'info',
     1275                    'ConvesioPay Reconciliation refund handler - order refresh missing.',
     1276                    array(
     1277                        'event'     => 'payments.convesiopay_reconciliation.refund.success',
     1278                        'component' => 'payments',
     1279                        'feature'   => 'convesiopay_reconciliation',
     1280                        'operation' => 'refund',
     1281                        'outcome'   => 'success',
     1282                        'method'    => __METHOD__,
     1283                        'line'      => __LINE__,
     1284                        'data'      => array(
     1285                            'details' => 'PeachPay Reconciliation: Order #' . $order_id . ' handled payment refund (order not found after refresh)'
     1286                )));
    9001287                return;
    9011288            }
     
    9091296                // Full refund - update order status to refunded
    9101297                $order->update_status( 'refunded', 'Order fully refunded via ConvesioPay Dashboard.' );
    911                 peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment refund (Full refund)' );
     1298                peachpay_log(
     1299                    'info',
     1300                    'ConvesioPay Reconciliation refund handler - full refund applied.',
     1301                    array(
     1302                        'event'     => 'payments.convesiopay_reconciliation.refund.success',
     1303                        'component' => 'payments',
     1304                        'feature'   => 'convesiopay_reconciliation',
     1305                        'operation' => 'refund',
     1306                        'outcome'   => 'success',
     1307                        'method'    => __METHOD__,
     1308                        'line'      => __LINE__,
     1309                        'data'      => array(
     1310                            'details' => 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment refund (Full refund)'
     1311                )));
    9121312            } else {
    9131313                // Partial refund - add informative note
     
    9211321                    $refund_percentage
    9221322                ) );
    923                 peachpay_log( 'info', 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment refund (Partial refund)' );
     1323                peachpay_log(
     1324                    'info',
     1325                    'ConvesioPay Reconciliation refund handler - partial refund applied.',
     1326                    array(
     1327                        'event'     => 'payments.convesiopay_reconciliation.refund.success',
     1328                        'component' => 'payments',
     1329                        'feature'   => 'convesiopay_reconciliation',
     1330                        'operation' => 'refund',
     1331                        'outcome'   => 'success',
     1332                        'method'    => __METHOD__,
     1333                        'line'      => __LINE__,
     1334                        'data'      => array(
     1335                            'details' => 'PeachPay Reconciliation: Order #' . $order->get_id() . ' handled payment refund (Partial refund)'
     1336                )));
    9241337            }
    9251338
     
    10041417        $message = 'PeachPay Reconciliation: Exception - ' . $context . ' - ' . $e->getMessage();
    10051418        $message .= ' in ' . $e->getFile() . ':' . $e->getLine();
    1006         peachpay_log( 'error', $message . "\n" . $e->getTraceAsString() );
     1419        peachpay_log(
     1420            'error',
     1421            'ConvesioPay Reconciliation exception handler - failed.',
     1422            array(
     1423                'event'     => 'payments.convesiopay_reconciliation.reconciliation_error.failed',
     1424                'component' => 'payments',
     1425                'feature'   => 'convesiopay_reconciliation',
     1426                'operation' => 'reconciliation_error',
     1427                'outcome'   => 'failed',
     1428                'method'    => __METHOD__,
     1429                'line'      => __LINE__,
     1430                'data'      => array(
     1431                    'details' => $message . "\n" . $e->getTraceAsString()
     1432        )));
    10071433    }
    10081434
     
    10161442                $timestamp = wp_next_scheduled(PEACHPAY_CONVESIOPAY_RECONCILE_CRON_HOOK);
    10171443                wp_unschedule_event($timestamp, PEACHPAY_CONVESIOPAY_RECONCILE_CRON_HOOK);
    1018                 peachpay_log( 'info', 'PeachPay Reconciliation: Unscheduled cron event' );
     1444                peachpay_log(
     1445                    'info',
     1446                    'ConvesioPay Reconciliation cron unschedule - completed.',
     1447                    array(
     1448                        'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     1449                        'component' => 'payments',
     1450                        'feature'   => 'convesiopay_reconciliation',
     1451                        'operation' => 'reconciliation',
     1452                        'outcome'   => 'success',
     1453                        'method'    => __METHOD__,
     1454                        'line'      => __LINE__,
     1455                    )
     1456                );
    10191457            }
    10201458        } catch ( \Throwable $e ) {
    10211459            $message = 'PeachPay Reconciliation: unschedule_cron - ' . $e->getMessage();
    10221460            $message .= ' in ' . $e->getFile() . ':' . $e->getLine();
    1023             peachpay_log( 'error', $message . "\n" . $e->getTraceAsString() );
     1461            peachpay_log(
     1462                'error',
     1463                'ConvesioPay Reconciliation cron unschedule - failed.',
     1464                array(
     1465                    'event'     => 'payments.convesiopay_reconciliation.reconciliation_error.failed',
     1466                    'component' => 'payments',
     1467                    'feature'   => 'convesiopay_reconciliation',
     1468                    'operation' => 'reconciliation_error',
     1469                    'outcome'   => 'failed',
     1470                    'method'    => __METHOD__,
     1471                    'line'      => __LINE__,
     1472                    'data'      => array(
     1473                        'details' => $message . "\n" . $e->getTraceAsString()
     1474            )));
    10241475        }
    10251476    }
     
    10321483{
    10331484    PeachPay_ConvesioPay_Reconciliation::unschedule_cron();
    1034     peachpay_log( 'info', 'PeachPay Reconciliation: Unscheduled cron event on plugin deactivation' );
     1485    peachpay_log(
     1486        'info',
     1487        'ConvesioPay Reconciliation deactivation unschedule - completed.',
     1488        array(
     1489            'event'     => 'payments.convesiopay_reconciliation.reconciliation.success',
     1490            'component' => 'payments',
     1491            'feature'   => 'convesiopay_reconciliation',
     1492            'operation' => 'reconciliation',
     1493            'outcome'   => 'success',
     1494            'method'    => __METHOD__,
     1495            'line'      => __LINE__,
     1496        )
     1497    );
    10351498}
    10361499
  • peachpay-for-woocommerce/trunk/core/payments/convesiopay/routes/class-peachpay-convesiopay-webhook.php

    r3486472 r3490786  
    107107        } catch ( \Throwable $e ) {
    108108            error_log( '[PP-WEBHOOK] PeachPay Webhook: Failed to get config - ' . $e->getMessage() );
    109             peachpay_log( 'error', 'PeachPay Webhook: Failed to get config - ' . $e->getMessage() );
     109            peachpay_log(
     110                'error',
     111                'ConvesioPay Webhook config load - failed.',
     112                array(
     113                    'event'     => 'webhooks.convesiopay.webhook.process.failed',
     114                    'component' => 'webhooks',
     115                    'feature'   => 'convesiopay',
     116                    'operation' => 'webhook.process',
     117                    'outcome'   => 'failed',
     118                    'method'    => __METHOD__,
     119                    'line'      => __LINE__,
     120                    'data'      => array(
     121                        'details' => 'PeachPay Webhook: Failed to get config - ' . $e->getMessage()
     122                    )
     123                )
     124            );
    110125            return new WP_REST_Response(
    111126                array(
     
    152167       
    153168
    154         peachpay_log( 'debug', 'PeachPay Webhook: Received event=' . $event_type . ' order_number=' . $order_number . ' payment_id=' . $payment_id );
     169        peachpay_log(
     170                'debug',
     171                'ConvesioPay Webhook request received - debug.',
     172                array(
     173                'event'     => 'webhooks.convesiopay.webhook.process.debug',
     174                'component' => 'webhooks',
     175                'feature'   => 'convesiopay',
     176                'operation' => 'webhook.process',
     177                'outcome'   => 'debug',
     178                'method'    => __METHOD__,
     179                'line'      => __LINE__,
     180                'data'      => array(
     181                    'details' => 'PeachPay Webhook: Received event=' . $event_type . ' order_number=' . $order_number . ' payment_id=' . $payment_id
     182                )
     183            )
     184        );
    155185
    156186        // Validate webhook signature (ConvesioPay documentation requirement)
    157187        if ( ! $this->validate_webhook_signature( $request ) ) {
    158188            error_log( '[PP-WEBHOOK] PeachPay Webhook: Invalid signature' );
    159             peachpay_log( 'error', 'PeachPay Webhook: Invalid signature' );
     189            peachpay_log(
     190                'error',
     191                'ConvesioPay Webhook signature validation - failed.',
     192                array(
     193                    'event'     => 'webhooks.convesiopay.webhook.process.failed',
     194                    'component' => 'webhooks',
     195                    'feature'   => 'convesiopay',
     196                    'operation' => 'webhook.process',
     197                    'outcome'   => 'failed',
     198                    'method'    => __METHOD__,
     199                    'line'      => __LINE__,
     200                )
     201            );
    160202            return new WP_REST_Response( array( 'error' => 'Invalid signature' ), 401 );
    161203        }
    162         peachpay_log( 'info', 'PeachPay Webhook: Signature valid for event=' . $event_type . ' order_number=' . $order_number );
    163204
    164205        // Validate webhook (basic validation)
    165206        if ( empty( $webhook_data ) ) {
    166             error_log( '[PP-WEBHOOK] PeachPay Webhook: Invalid webhook data' );
    167             peachpay_log( 'error', 'PeachPay Webhook: Invalid webhook data' );
     207            peachpay_log(
     208                'error',
     209                'ConvesioPay Webhook payload validation - failed.',
     210                array(
     211                    'event'     => 'webhooks.convesiopay.webhook.process.failed',
     212                    'component' => 'webhooks',
     213                    'feature'   => 'convesiopay',
     214                    'operation' => 'webhook.process',
     215                    'outcome'   => 'failed',
     216                    'method'    => __METHOD__,
     217                    'line'      => __LINE__,
     218                )
     219            );
    168220            return new WP_REST_Response( array( 'error' => 'Invalid webhook data' ), 400 );
    169221        }
     
    171223        // Check for duplicate events (ConvesioPay documentation requirement)
    172224        if ( $this->is_duplicate_event( $webhook_data ) ) {
    173             peachpay_log( 'info', 'PeachPay Webhook: Duplicate event skipped' );
     225            peachpay_log(
     226                'info',
     227                'ConvesioPay Webhook duplicate event check - already processed.',
     228                array(
     229                    'event'     => 'webhooks.convesiopay.webhook.process.success',
     230                    'component' => 'webhooks',
     231                    'feature'   => 'convesiopay',
     232                    'operation' => 'webhook.process',
     233                    'outcome'   => 'success',
     234                    'method'    => __METHOD__,
     235                    'line'      => __LINE__,
     236                    'data'      => array(
     237                        'details' => 'PeachPay Webhook: Duplicate event found for event=' . $event_type . ' order_number=' . $order_number,
     238                        'webhook_data' => $webhook_data
     239                    )
     240                )
     241            );
    174242            return new WP_REST_Response( array( 'status' => 'duplicate_skipped' ), 200 );
    175243        }
     
    208276            if ( ! $order ) {
    209277                error_log( '[PP-WEBHOOK] PeachPay Webhook: Order not found for orderNumber ' . $order_number );
    210                 peachpay_log( 'error', 'PeachPay Webhook: Order not found for orderNumber ' . $order_number );
     278                peachpay_log(
     279                    'error',
     280                    'ConvesioPay Webhook order lookup - failed.',
     281                    array(
     282                        'event'     => 'webhooks.convesiopay.webhook.process.failed',
     283                        'component' => 'webhooks',
     284                        'feature'   => 'convesiopay',
     285                        'operation' => 'webhook.process',
     286                        'outcome'   => 'failed',
     287                        'method'    => __METHOD__,
     288                        'line'      => __LINE__,
     289                        'data'      => array(
     290                            'details' => 'PeachPay Webhook: Order not found for orderNumber ' . $order_number
     291                        )
     292                    )
     293                );
    211294                return new WP_REST_Response( array( 'error' => 'Order not found' ), 404 );
    212295            }
    213             peachpay_log( 'debug', 'PeachPay Webhook: Order found for orderNumber ' . $order_number . ' => order #' . $order->get_id() . ' (display number ' . $order->get_order_number() . ')' );
     296
     297            peachpay_log(
     298                'debug',
     299                'ConvesioPay Webhook order lookup - order found.',
     300                array(
     301                    'event'     => 'webhooks.convesiopay.webhook.process.debug',
     302                    'component' => 'webhooks',
     303                    'feature'   => 'convesiopay',
     304                    'operation' => 'webhook.process',
     305                    'outcome'   => 'debug',
     306                    'method'    => __METHOD__,
     307                    'line'      => __LINE__,
     308                    'data'      => array(
     309                        'details' => 'PeachPay Webhook: Order found for orderNumber ' . $order_number . ' => order #' . $order->get_id() . ' (display number ' . $order->get_order_number() . ')'
     310                    )
     311                )
     312            );
    214313
    215314            // SECURITY: Validate that the order belongs to ConvesioPay before processing
     
    222321                    if ( (string) $stored_payment_id === (string) $payment_id ) {
    223322                        $is_convesiopay = true;
    224                         peachpay_log( 'debug', 'PeachPay Webhook: Order #' . $order->get_id() . ' accepted via fallback (webhook paymentId matches _convesiopay_payment_id)' );
     323                        peachpay_log(
     324                            'debug',
     325                            'ConvesioPay Webhook order validation fallback - payment ID matched.',
     326                            array(
     327                                'event'     => 'webhooks.convesiopay.webhook.process.debug',
     328                                'component' => 'webhooks',
     329                                'feature'   => 'convesiopay',
     330                                'operation' => 'webhook.process',
     331                                'outcome'   => 'debug',
     332                                'method'    => __METHOD__,
     333                                'line'      => __LINE__,
     334                                'data'      => array(
     335                                    'details' => 'PeachPay Webhook: Order #' . $order->get_id() . ' accepted via fallback (webhook paymentId matches _convesiopay_payment_id)'
     336                                )
     337                            )
     338                        );
    225339                    } else {
    226                         peachpay_log( 'debug', 'PeachPay Webhook: Order #' . $order->get_id() . ' fallback did not match: stored _convesiopay_payment_id=' . (string) $stored_payment_id . ' webhook paymentId=' . (string) $payment_id );
     340                        peachpay_log(
     341                            'debug',
     342                            'ConvesioPay Webhook order validation fallback - payment ID mismatch.',
     343                            array(
     344                                'event'     => 'webhooks.convesiopay.webhook.process.debug',
     345                                'component' => 'webhooks',
     346                                'feature'   => 'convesiopay',
     347                                'operation' => 'webhook.process',
     348                                'outcome'   => 'debug',
     349                                'method'    => __METHOD__,
     350                                'line'      => __LINE__,
     351                                'data'      => array(
     352                                    'details' => 'PeachPay Webhook: Order #' . $order->get_id() . ' fallback did not match: stored _convesiopay_payment_id=' . (string) $stored_payment_id . ' webhook paymentId=' . (string) $payment_id
     353                                )
     354                            )
     355                        );
    227356                    }
    228357                } else {
    229                     peachpay_log( 'debug', 'PeachPay Webhook: Order #' . $order->get_id() . ' fallback skipped: _convesiopay_payment_id empty or non-scalar, webhook paymentId=' . (string) $payment_id );
     358                    peachpay_log(
     359                        'debug',
     360                        'ConvesioPay Webhook order validation fallback - skipped.',
     361                        array(
     362                            'event'     => 'webhooks.convesiopay.webhook.process.debug',
     363                            'component' => 'webhooks',
     364                            'feature'   => 'convesiopay',
     365                            'operation' => 'webhook.process',
     366                            'outcome'   => 'debug',
     367                            'method'    => __METHOD__,
     368                            'line'      => __LINE__,
     369                            'data'      => array(
     370                                'details' => 'PeachPay Webhook: Order #' . $order->get_id() . ' fallback skipped: _convesiopay_payment_id empty or non-scalar, webhook paymentId=' . (string) $payment_id
     371                            )
     372                        )
     373                    );
    230374                }
    231375            }
    232376            if ( ! $is_convesiopay ) {
    233                 peachpay_log( 'warning', 'PeachPay Webhook: Rejected - non-ConvesioPay order #' . $order->get_id() . ' (order_number=' . $order_number . ' payment_id=' . $payment_id . '). Check is_convesiopay_order() logs above for reason.' );
     377                peachpay_log(
     378                    'warning',
     379                    'ConvesioPay Webhook order validation - rejected non-ConvesioPay order.',
     380                    array(
     381                        'event'     => 'webhooks.convesiopay.webhook.process.warning',
     382                        'component' => 'webhooks',
     383                        'feature'   => 'convesiopay',
     384                        'operation' => 'webhook.process',
     385                        'outcome'   => 'warning',
     386                        'method'    => __METHOD__,
     387                        'line'      => __LINE__,
     388                        'data'      => array(
     389                            'details' => 'PeachPay Webhook: Rejected - non-ConvesioPay order #' . $order->get_id() . ' (order_number=' . $order_number . ' payment_id=' . $payment_id . '). Check is_convesiopay_order() logs above for reason.'
     390                        )
     391                    )
     392                );
    234393                return new WP_REST_Response( array( 'error' => 'Order does not belong to ConvesioPay' ), 403 );
    235394            }
     
    242401        } catch ( \Throwable $e ) {
    243402            error_log( '[PP-WEBHOOK] PeachPay Webhook: Failed to process - ' . $e->getMessage() );
    244             peachpay_log( 'error', 'PeachPay Webhook: Failed to process - ' . $e->getMessage() );
     403            peachpay_log(
     404                'error',
     405                'ConvesioPay Webhook processing - failed.',
     406                array(
     407                    'event'     => 'webhooks.convesiopay.webhook.process.failed',
     408                    'component' => 'webhooks',
     409                    'feature'   => 'convesiopay',
     410                    'operation' => 'webhook.process',
     411                    'outcome'   => 'failed',
     412                    'method'    => __METHOD__,
     413                    'line'      => __LINE__,
     414                    'data'      => array(
     415                        'details' => 'PeachPay Webhook: Failed to process - ' . $e->getMessage()
     416                    )
     417                )
     418            );
    245419            return new WP_REST_Response( array( 'error' => 'Webhook processing failed' ), 500 );
    246420        }
     
    256430        if ( ! $order ) {
    257431            error_log( '[PP-WEBHOOK] PeachPay Webhook: is_convesiopay_order() failed - order is null/empty' );
    258             peachpay_log( 'error', 'PeachPay Webhook: is_convesiopay_order() failed - order is null/empty' );
    259432            return false;
    260433        }
     
    265438            if ( ! $parent_id ) {
    266439                error_log( '[PP-WEBHOOK] PeachPay Webhook: is_convesiopay_order() failed - refund order #' . $order->get_id() . ' has no parent_id' );
    267                 peachpay_log( 'error', 'PeachPay Webhook: is_convesiopay_order() failed - refund order #' . $order->get_id() . ' has no parent_id' );
     440                peachpay_log(
     441                    'error',
     442                    'ConvesioPay Webhook refund validation - missing parent order id.',
     443                    array(
     444                        'event'     => 'webhooks.convesiopay.refund.failed',
     445                        'component' => 'webhooks',
     446                        'feature'   => 'convesiopay',
     447                        'operation' => 'refund',
     448                        'outcome'   => 'failed',
     449                        'method'    => __METHOD__,
     450                        'line'      => __LINE__,
     451                        'data'      => array(
     452                            'details' => 'PeachPay Webhook: is_convesiopay_order() failed - refund order #' . $order->get_id() . ' has no parent_id'
     453                        )
     454                    )
     455                );
    268456                return false;
    269457            }
     
    271459            if ( ! $order ) {
    272460                error_log( '[PP-WEBHOOK] PeachPay Webhook: is_convesiopay_order() failed - parent order #' . $parent_id . ' not found' );
    273                 peachpay_log( 'error', 'PeachPay Webhook: is_convesiopay_order() failed - parent order #' . $parent_id . ' not found' );
     461                peachpay_log(
     462                    'error',
     463                    'ConvesioPay Webhook order validation - missing parent order.',
     464                    array(
     465                        'event'     => 'webhooks.convesiopay.webhook.process.failed',
     466                        'component' => 'webhooks',
     467                        'feature'   => 'convesiopay',
     468                        'operation' => 'webhook.process',
     469                        'outcome'   => 'failed',
     470                        'method'    => __METHOD__,
     471                        'line'      => __LINE__,
     472                        'data'      => array(
     473                            'details' => 'PeachPay Webhook: is_convesiopay_order() failed - parent order #' . $parent_id . ' not found'
     474                        )
     475                    )
     476                );
    274477                return false;
    275478            }
     
    285488        // Log once with all key values so we can see why the order passed or failed
    286489        $log_payment_id = ( is_scalar( $convesiopay_payment_id ) && (string) $convesiopay_payment_id !== '' ) ? (string) $convesiopay_payment_id : '(empty)';
    287         peachpay_log( 'debug', 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' payment_method=' . ( $payment_method !== '' ? $payment_method : '(empty)' ) . ' _original_payment_method=' . ( is_string( $original_payment_method ) && $original_payment_method !== '' ? $original_payment_method : '(empty)' ) . ' _convesiopay_payment_id=' . $log_payment_id );
     490        peachpay_log(
     491            'debug',
     492            'ConvesioPay Webhook order validation - inspect order context.',
     493            array(
     494                'event'     => 'webhooks.convesiopay.webhook.process.debug',
     495                'component' => 'webhooks',
     496                'feature'   => 'convesiopay',
     497                'operation' => 'webhook.process',
     498                'outcome'   => 'debug',
     499                'method'    => __METHOD__,
     500                'line'      => __LINE__,
     501                'data'      => array(
     502                    'details' => 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' payment_method=' . ( $payment_method !== '' ? $payment_method : '(empty)' ) . ' _original_payment_method=' . ( is_string( $original_payment_method ) && $original_payment_method !== '' ? $original_payment_method : '(empty)' ) . ' _convesiopay_payment_id=' . $log_payment_id
     503                )
     504            )
     505        );
    288506       
    289507        // Check if the payment method is a ConvesioPay gateway
    290508        if ( class_exists( 'PeachPay_ConvesioPay_Integration' ) && method_exists( 'PeachPay_ConvesioPay_Integration', 'is_payment_gateway' ) ) {
    291509            if ( PeachPay_ConvesioPay_Integration::is_payment_gateway( $payment_method ) ) {
    292                 peachpay_log( 'debug', 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => true (payment_method is ConvesioPay gateway)' );
     510                peachpay_log(
     511                    'debug',
     512                    'ConvesioPay Webhook order validation - payment method matched.',
     513                    array(
     514                        'event'     => 'webhooks.convesiopay.webhook.process.debug',
     515                        'component' => 'webhooks',
     516                        'feature'   => 'convesiopay',
     517                        'operation' => 'webhook.process',
     518                        'outcome'   => 'debug',
     519                        'method'    => __METHOD__,
     520                        'line'      => __LINE__,
     521                        'data'      => array(
     522                            'details' => 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => true (payment_method is ConvesioPay gateway)'
     523                        )
     524                    )
     525                );
    293526                return true;
    294527            }
    295528            // Unified checkout may store original gateway before redirecting to card/btcpay/applepay
    296529            if ( is_string( $original_payment_method ) && $original_payment_method !== '' && PeachPay_ConvesioPay_Integration::is_payment_gateway( $original_payment_method ) ) {
    297                 peachpay_log( 'debug', 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => true (_original_payment_method is ConvesioPay gateway)' );
     530                peachpay_log(
     531                    'debug',
     532                    'ConvesioPay Webhook order validation - original payment method matched.',
     533                    array(
     534                        'event'     => 'webhooks.convesiopay.webhook.process.debug',
     535                        'component' => 'webhooks',
     536                        'feature'   => 'convesiopay',
     537                        'operation' => 'webhook.process',
     538                        'outcome'   => 'debug',
     539                        'method'    => __METHOD__,
     540                        'line'      => __LINE__,
     541                        'data'      => array(
     542                            'details' => 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => true (_original_payment_method is ConvesioPay gateway)'
     543                        )
     544                    )
     545                );
    298546                return true;
    299547            }
     
    302550        // Check if order has ConvesioPay payment ID stored
    303551        if ( is_string( $convesiopay_payment_id ) && $convesiopay_payment_id !== '' ) {
    304             peachpay_log( 'debug', 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => true (_convesiopay_payment_id meta set)' );
     552            peachpay_log(
     553                'debug',
     554                'ConvesioPay Webhook order validation - payment meta matched.',
     555                array(
     556                    'event'     => 'webhooks.convesiopay.webhook.process.debug',
     557                    'component' => 'webhooks',
     558                    'feature'   => 'convesiopay',
     559                    'operation' => 'webhook.process',
     560                    'outcome'   => 'debug',
     561                    'method'    => __METHOD__,
     562                    'line'      => __LINE__,
     563                    'data'      => array(
     564                        'details' => 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => true (_convesiopay_payment_id meta set)'
     565                    )
     566                )
     567            );
    305568            return true;
    306569        }
    307570        if ( is_numeric( $convesiopay_payment_id ) && (string) $convesiopay_payment_id !== '' ) {
    308             peachpay_log( 'debug', 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => true (_convesiopay_payment_id meta set)' );
     571            peachpay_log(
     572                'debug',
     573                'ConvesioPay Webhook order validation - numeric payment meta matched.',
     574                array(
     575                    'event'     => 'webhooks.convesiopay.webhook.process.debug',
     576                    'component' => 'webhooks',
     577                    'feature'   => 'convesiopay',
     578                    'operation' => 'webhook.process',
     579                    'outcome'   => 'debug',
     580                    'method'    => __METHOD__,
     581                    'line'      => __LINE__,
     582                    'data'      => array(
     583                        'details' => 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => true (_convesiopay_payment_id meta set)'
     584                    )
     585                )
     586            );
    309587            return true;
    310588        }
     
    315593            if ( class_exists( 'PeachPay_ConvesioPay_Integration' ) && method_exists( 'PeachPay_ConvesioPay_Integration', 'connected' ) ) {
    316594                $connected = PeachPay_ConvesioPay_Integration::connected();
    317                 peachpay_log( 'debug', 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => ' . ( $connected ? 'true' : 'false' ) . ' (empty payment_method, ConvesioPay connected=' . ( $connected ? 'yes' : 'no' ) . ')' );
     595                peachpay_log(
     596                    'debug',
     597                    'ConvesioPay Webhook order validation - connected fallback check.',
     598                    array(
     599                        'event'     => 'webhooks.convesiopay.webhook.process.debug',
     600                        'component' => 'webhooks',
     601                        'feature'   => 'convesiopay',
     602                        'operation' => 'webhook.process',
     603                        'outcome'   => 'debug',
     604                        'method'    => __METHOD__,
     605                        'line'      => __LINE__,
     606                        'data'      => array(
     607                            'details' => 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => ' . ( $connected ? 'true' : 'false' ) . ' (empty payment_method, ConvesioPay connected=' . ( $connected ? 'yes' : 'no' ) . ')'
     608                        )
     609                    )
     610                );
    318611                return $connected;
    319612            }
    320613        }
    321        
    322         peachpay_log( 'debug', 'PeachPay Webhook: is_convesiopay_order() order #' . $order_id . ' => false (no ConvesioPay gateway, no _convesiopay_payment_id, empty payment_method or ConvesioPay not connected)' );
    323614        return false;
    324615    }
     
    339630        $hpos_active_bool = ( class_exists( \Automattic\WooCommerce\Utilities\OrderUtil::class ) && \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() );
    340631        $hpos_active      = $hpos_active_bool ? 'yes' : 'no';
    341         peachpay_log( 'info', 'PeachPay Webhook [find_order_by_number]: called with order_number=' . $order_number . ', payment_id=' . ( ! empty( $payment_id ) ? $payment_id : '(none)' ) . ', HPOS=' . $hpos_active );
     632        peachpay_log(
     633            'info',
     634            'ConvesioPay Webhook order lookup - started.',
     635            array(
     636                'event'     => 'webhooks.convesiopay.webhook.process.success',
     637                'component' => 'webhooks',
     638                'feature'   => 'convesiopay',
     639                'operation' => 'webhook.process',
     640                'outcome'   => 'success',
     641                'method'    => __METHOD__,
     642                'line'      => __LINE__,
     643                'data'      => array(
     644                    'details' => 'PeachPay Webhook [find_order_by_number]: called with order_number=' . $order_number . ', payment_id=' . ( ! empty( $payment_id ) ? $payment_id : '(none)' ) . ', HPOS=' . $hpos_active
     645                )
     646            )
     647        );
    342648        $order_id_int     = (int) $order_number;
    343649        $is_numeric       = ( (string) $order_id_int === $order_number_str && $order_id_int > 0 );
     
    361667            );
    362668            if ( ! empty( $orders ) ) {
    363                 peachpay_log( 'debug', 'PeachPay Webhook: find_order_by_number(' . $order_number . ') resolved by _convesiopay_payment_id meta => order #' . $orders[0]->get_id() );
     669                peachpay_log(
     670                    'debug',
     671                    'ConvesioPay Webhook order lookup - payment ID matched order.',
     672                    array(
     673                        'event'     => 'webhooks.convesiopay.webhook.process.debug',
     674                        'component' => 'webhooks',
     675                        'feature'   => 'convesiopay',
     676                        'operation' => 'webhook.process',
     677                        'outcome'   => 'debug',
     678                        'method'    => __METHOD__,
     679                        'line'      => __LINE__,
     680                        'data'      => array(
     681                            'details' => 'PeachPay Webhook: find_order_by_number(' . $order_number . ') resolved by _convesiopay_payment_id meta => order #' . $orders[0]->get_id()
     682                        )
     683                    )
     684                );
    364685                return $orders[0];
    365686            }
    366             peachpay_log( 'info', 'PeachPay Webhook [find_order_by_number]: Step 0 found no match for payment_id=' . $payment_id . '; falling through to Step 1' );
     687            peachpay_log(
     688                'info',
     689                'ConvesioPay Webhook order lookup - payment ID step no match.',
     690                array(
     691                    'event'     => 'webhooks.convesiopay.webhook.process.success',
     692                    'component' => 'webhooks',
     693                    'feature'   => 'convesiopay',
     694                    'operation' => 'webhook.process',
     695                    'outcome'   => 'success',
     696                    'method'    => __METHOD__,
     697                    'line'      => __LINE__,
     698                    'data'      => array(
     699                        'details' => 'PeachPay Webhook [find_order_by_number]: Step 0 found no match for payment_id=' . $payment_id . '; falling through to Step 1'
     700                    )
     701                )
     702            );
    367703        } else {
    368704            $skip_reason = empty( $payment_id ) ? 'no payment_id provided' : 'HPOS disabled';
    369             peachpay_log( 'info', 'PeachPay Webhook [find_order_by_number]: Step 0 skipped — ' . $skip_reason . '; falling through to Step 1' );
     705            peachpay_log(
     706                'info',
     707                'ConvesioPay Webhook order lookup - payment ID step skipped.',
     708                array(
     709                    'event'     => 'webhooks.convesiopay.webhook.process.success',
     710                    'component' => 'webhooks',
     711                    'feature'   => 'convesiopay',
     712                    'operation' => 'webhook.process',
     713                    'outcome'   => 'success',
     714                    'method'    => __METHOD__,
     715                    'line'      => __LINE__,
     716                    'data'      => array(
     717                        'details' => 'PeachPay Webhook [find_order_by_number]: Step 0 skipped — ' . $skip_reason . '; falling through to Step 1'
     718                    )
     719                )
     720            );
    370721        }
    371722
     
    380731            $candidate = $orders[0];
    381732            if ( strval( $candidate->get_order_number() ) === $order_number_str ) {
    382                 peachpay_log( 'debug', 'PeachPay Webhook: find_order_by_number(' . $order_number . ') resolved by order_number param (display) => order #' . $candidate->get_id() );
     733                peachpay_log(
     734                    'debug',
     735                    'ConvesioPay Webhook order lookup - display number matched order.',
     736                    array(
     737                        'event'     => 'webhooks.convesiopay.webhook.process.debug',
     738                        'component' => 'webhooks',
     739                        'feature'   => 'convesiopay',
     740                        'operation' => 'webhook.process',
     741                        'outcome'   => 'debug',
     742                        'method'    => __METHOD__,
     743                        'line'      => __LINE__,
     744                        'data'      => array(
     745                            'details' => 'PeachPay Webhook: find_order_by_number(' . $order_number . ') resolved by order_number param (display) => order #' . $candidate->get_id()
     746                        )
     747                    )
     748                );
    383749                return $candidate;
    384750            }
    385             peachpay_log( 'debug', 'PeachPay Webhook: find_order_by_number(' . $order_number . ') order_number param returned order #' . $candidate->get_id() . ' (display ' . $candidate->get_order_number() . ') – no match' );
    386             peachpay_log( 'info', 'PeachPay Webhook [find_order_by_number]: Step 1 found no display-number match; falling through to Step 2' );
     751            peachpay_log(
     752                'debug',
     753                'ConvesioPay Webhook order lookup - display number mismatch.',
     754                array(
     755                    'event'     => 'webhooks.convesiopay.webhook.process.debug',
     756                    'component' => 'webhooks',
     757                    'feature'   => 'convesiopay',
     758                    'operation' => 'webhook.process',
     759                    'outcome'   => 'debug',
     760                    'method'    => __METHOD__,
     761                    'line'      => __LINE__,
     762                    'data'      => array(
     763                        'details' => 'PeachPay Webhook: find_order_by_number(' . $order_number . ') order_number param returned order #' . $candidate->get_id() . ' (display ' . $candidate->get_order_number() . ') – no match'
     764                    )
     765                )
     766            );
    387767        } else {
    388             peachpay_log( 'info', 'PeachPay Webhook [find_order_by_number]: Step 1 returned no orders; falling through to Step 2' );
     768            peachpay_log(
     769                'info',
     770                'ConvesioPay Webhook order lookup - wc_get_order step no match.',
     771                array(
     772                    'event'     => 'webhooks.convesiopay.webhook.process.success',
     773                    'component' => 'webhooks',
     774                    'feature'   => 'convesiopay',
     775                    'operation' => 'webhook.process',
     776                    'outcome'   => 'success',
     777                    'method'    => __METHOD__,
     778                    'line'      => __LINE__,
     779                )
     780            );
    389781        }
    390782
     
    405797            }
    406798            if ( strval( $check_order->get_order_number() ) === $order_number_str ) {
    407                 peachpay_log( 'debug', 'PeachPay Webhook: find_order_by_number(' . $order_number . ') resolved by get_order_number() => order #' . $check_order->get_id() );
     799                peachpay_log(
     800                'debug',
     801                'ConvesioPay Webhook order lookup - recent orders match found.',
     802                array(
     803                        'event'     => 'webhooks.convesiopay.webhook.process.debug',
     804                        'component' => 'webhooks',
     805                        'feature'   => 'convesiopay',
     806                        'operation' => 'webhook.process',
     807                        'outcome'   => 'debug',
     808                        'method'    => __METHOD__,
     809                        'line'      => __LINE__,
     810                'data'      => array(
     811                    'details' => 'PeachPay Webhook: find_order_by_number(' . $order_number . ') resolved by get_order_number() => order #' . $check_order->get_id()
     812                )));
    408813                return $check_order;
    409814            }
    410815        }
    411         peachpay_log( 'info', 'PeachPay Webhook [find_order_by_number]: Step 2 exhausted after checking ' . count( $recent_order_ids ) . ' orders; no match found' );
     816
     817        peachpay_log(
     818            'info',
     819            'ConvesioPay Webhook order lookup - no match found.',
     820            array(
     821                'event'     => 'webhooks.convesiopay.webhook.process.success',
     822                'component' => 'webhooks',
     823                'feature'   => 'convesiopay',
     824                'operation' => 'webhook.process',
     825                'outcome'   => 'success',
     826                'method'    => __METHOD__,
     827                'line'      => __LINE__,
     828                'data'      => array(
     829                    'details' => 'PeachPay Webhook [find_order_by_number]: Step 2 exhausted after checking ' . count( $recent_order_ids ) . ' orders; no match found'
     830                )
     831            )
     832        );
    412833
    413834        // 3) Fallback: treat as order ID (e.g. stored-card renewal sends get_id()).
     
    415836            $order_by_id = wc_get_order( $order_id_int );
    416837            if ( $order_by_id && is_a( $order_by_id, 'WC_Order' ) && ! is_a( $order_by_id, 'WC_Order_Refund' ) ) {
    417                 peachpay_log( 'debug', 'PeachPay Webhook: find_order_by_number(' . $order_number . ') resolved by order ID => order #' . $order_by_id->get_id() );
     838                peachpay_log(
     839                    'debug',
     840                    'ConvesioPay Webhook order lookup - order ID matched order.',
     841                    array(
     842                        'event'     => 'webhooks.convesiopay.webhook.process.debug',
     843                        'component' => 'webhooks',
     844                        'feature'   => 'convesiopay',
     845                        'operation' => 'webhook.process',
     846                        'outcome'   => 'debug',
     847                        'method'    => __METHOD__,
     848                        'line'      => __LINE__,
     849                        'data'      => array(
     850                            'details' => 'PeachPay Webhook: find_order_by_number(' . $order_number . ') resolved by order ID => order #' . $order_by_id->get_id()
     851                        )
     852                    )
     853                );
    418854                return $order_by_id;
    419855            }
    420856        }
    421857
    422         peachpay_log( 'debug', 'PeachPay Webhook: find_order_by_number(' . $order_number . ') no order found' );
     858        peachpay_log(
     859            'debug',
     860            'ConvesioPay Webhook order lookup - no order found.',
     861            array(
     862                'event'     => 'webhooks.convesiopay.webhook.process.debug',
     863                'component' => 'webhooks',
     864                'feature'   => 'convesiopay',
     865                'operation' => 'webhook.process',
     866                'outcome'   => 'debug',
     867                'method'    => __METHOD__,
     868                'line'      => __LINE__,
     869                'data'      => array(
     870                    'details' => 'PeachPay Webhook: find_order_by_number(' . $order_number . ') no order found'
     871                )
     872            )
     873        );
    423874        return false;
    424875    }
     
    11231574        if ( empty( $convesiopay_timestamp ) || empty( $convesiopay_signature ) ) {
    11241575            error_log( '[PP-WEBHOOK] PeachPay Webhook: Missing required signature headers - rejecting webhook' );
    1125             peachpay_log( 'error', 'PeachPay Webhook: Missing required signature headers - rejecting webhook' );
     1576            peachpay_log(
     1577                'error',
     1578                'ConvesioPay Webhook signature headers - missing.',
     1579                array(
     1580                    'event'     => 'webhooks.convesiopay.webhook.process.failed',
     1581                    'component' => 'webhooks',
     1582                    'feature'   => 'convesiopay',
     1583                    'operation' => 'webhook.process',
     1584                    'outcome'   => 'failed',
     1585                    'method'    => __METHOD__,
     1586                    'line'      => __LINE__,
     1587                )
     1588            );
    11261589            return false;
    11271590        }
     
    11351598        if ( empty( $webhook_signature_key ) ) {
    11361599            error_log( '[PP-WEBHOOK] PeachPay Webhook: No webhook signature key configured - rejecting webhook for security' );
    1137             peachpay_log( 'error', 'PeachPay Webhook: No webhook signature key configured - rejecting webhook for security' );
     1600            peachpay_log(
     1601                'error',
     1602                'ConvesioPay Webhook signature key - missing.',
     1603                array(
     1604                    'event'     => 'webhooks.convesiopay.webhook.process.failed',
     1605                    'component' => 'webhooks',
     1606                    'feature'   => 'convesiopay',
     1607                    'operation' => 'webhook.process',
     1608                    'outcome'   => 'failed',
     1609                    'method'    => __METHOD__,
     1610                    'line'      => __LINE__,
     1611                )
     1612            );
    11381613            return false;
    11391614        }
     
    11481623        if ( ! $is_valid ) {
    11491624            error_log( '[PP-WEBHOOK] PeachPay Webhook: Invalid signature - rejecting webhook' );
    1150             peachpay_log( 'error', 'PeachPay Webhook: Invalid signature - rejecting webhook' );
     1625            peachpay_log(
     1626                'error',
     1627                'ConvesioPay Webhook signature validation - mismatch.',
     1628                array(
     1629                    'event'     => 'webhooks.convesiopay.webhook.process.failed',
     1630                    'component' => 'webhooks',
     1631                    'feature'   => 'convesiopay',
     1632                    'operation' => 'webhook.process',
     1633                    'outcome'   => 'failed',
     1634                    'method'    => __METHOD__,
     1635                    'line'      => __LINE__,
     1636                )
     1637            );
    11511638        }
    11521639       
     
    11671654        if ( empty( $payment_id ) || empty( $event_type ) ) {
    11681655            error_log( '[PP-WEBHOOK] PeachPay Webhook: Missing payment ID or event type inside is_duplicate_event() Line : ' . __LINE__ );
    1169             peachpay_log( 'error', 'PeachPay Webhook: Missing payment ID or event type inside is_duplicate_event() Line : ' . __LINE__ );
     1656            peachpay_log(
     1657                'error',
     1658                'ConvesioPay Webhook duplicate event check - missing identifiers.',
     1659                array(
     1660                    'event'     => 'webhooks.convesiopay.webhook.process.failed',
     1661                    'component' => 'webhooks',
     1662                    'feature'   => 'convesiopay',
     1663                    'operation' => 'webhook.process',
     1664                    'outcome'   => 'failed',
     1665                    'method'    => __METHOD__,
     1666                    'line'      => __LINE__,
     1667                'data'      => array(
     1668                    'details' => 'PeachPay Webhook: Missing payment ID or event type inside is_duplicate_event() Line : ' . __LINE__
     1669                )));
    11701670            return false;
    11711671        }
     
    11791679       
    11801680        if ( $existing_event ) {
    1181             peachpay_log( 'debug', 'PeachPay Webhook: Duplicate event found inside is_duplicate_event() Line : ' . __LINE__ );
     1681            peachpay_log(
     1682                'debug',
     1683                'ConvesioPay Webhook duplicate event check - duplicate found.',
     1684                array(
     1685                    'event'     => 'webhooks.convesiopay.webhook.process.debug',
     1686                    'component' => 'webhooks',
     1687                    'feature'   => 'convesiopay',
     1688                    'operation' => 'webhook.process',
     1689                    'outcome'   => 'debug',
     1690                    'method'    => __METHOD__,
     1691                    'line'      => __LINE__,
     1692                'data'      => array(
     1693                    'details' => 'PeachPay Webhook: Duplicate event found inside is_duplicate_event() Line : ' . __LINE__
     1694                )));
    11821695            return true;
    11831696        }
     
    11891702        }
    11901703       
    1191         peachpay_log( 'debug', 'PeachPay Webhook: No duplicate event found inside is_duplicate_event() Line : ' . __LINE__ );
     1704        peachpay_log(
     1705                'debug',
     1706                'ConvesioPay Webhook duplicate event check - no duplicate found.',
     1707                array(
     1708                'event'     => 'webhooks.convesiopay.webhook.process.debug',
     1709                'component' => 'webhooks',
     1710                'feature'   => 'convesiopay',
     1711                'operation' => 'webhook.process',
     1712                'outcome'   => 'debug',
     1713                'method'    => __METHOD__,
     1714                'line'      => __LINE__,
     1715                'data'      => array(
     1716                    'details' => 'PeachPay Webhook: No duplicate event found inside is_duplicate_event() Line : ' . __LINE__
     1717                )));
    11921718        return false;
    11931719    }
  • peachpay-for-woocommerce/trunk/core/payments/stripe/abstract/class-peachpay-stripe-payment-gateway.php

    r3486614 r3490786  
    1919    use PeachPay_Stripe_Gateway_Utilities;
    2020
     21    /**
     22     * Track registered renewal hooks by hook name.
     23     *
     24     * @var array<string, bool>
     25     */
     26    private static $renewal_hooks_registered = array();
     27
    2128    public $payment_provider                         = 'Stripe';
    2229    public $min_amount                               = 0.50;
     
    4451
    4552        // Subscription support.
    46         $gateway = $this;
     53        $this->register_subscription_renewal_hook();
     54
     55        add_filter( 'woocommerce_gateway_title', array( $this, 'handle_payment_method_title_filter' ), 10, 2 );
     56    }
     57
     58    /**
     59     * Register subscription renewal hook once per request per gateway ID.
     60     */
     61    private function register_subscription_renewal_hook() {
     62        $hook_name = 'woocommerce_scheduled_subscription_payment_' . $this->id;
     63        if ( isset( self::$renewal_hooks_registered[ $hook_name ] ) ) {
     64            return;
     65        }
    4766        add_action(
    48             'woocommerce_scheduled_subscription_payment_' . $this->id,
    49             function ( $renewal_total, $renewal_order ) use ( $gateway ) {
    50                 $subscriptions = wcs_get_subscriptions_for_renewal_order( $renewal_order );
    51                 $subscription  = array_pop( $subscriptions );
    52                 $parent_order  = wc_get_order( $subscription->get_parent_id() );
    53 
    54                 $gateway->process_subscription_renewal( $parent_order, $renewal_order, $renewal_total );
    55             },
     67            $hook_name,
     68            array( $this, 'handle_subscription_renewal_payment' ),
    5669            10,
    5770            2
    5871        );
    59 
    60         add_filter( 'woocommerce_gateway_title', array( $this, 'handle_payment_method_title_filter' ), 10, 2 );
     72        self::$renewal_hooks_registered[ $hook_name ] = true;
     73    }
     74
     75    /**
     76     * Handle scheduled subscription renewal payment.
     77     *
     78     * @param float    $renewal_total Renewal amount.
     79     * @param WC_Order $renewal_order Renewal order.
     80     */
     81    public function handle_subscription_renewal_payment( $renewal_total, $renewal_order ) {
     82        if ( ! function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ) {
     83            return;
     84        }
     85
     86        $subscriptions = wcs_get_subscriptions_for_renewal_order( $renewal_order );
     87        $subscription  = array_pop( $subscriptions );
     88        if ( ! $subscription ) {
     89            return;
     90        }
     91
     92        $parent_order = wc_get_order( $subscription->get_parent_id() );
     93        if ( ! $parent_order ) {
     94            return;
     95        }
     96
     97        $this->process_subscription_renewal( $parent_order, $renewal_order, $renewal_total );
    6198    }
    6299
     
    246283            $stripe_customer = $this->get_stripe_customer( $user_id );
    247284            if ( $this->is_subscription_checkout_order( $order ) && empty( $stripe_customer ) ) {
    248                 peachpay_log( 'warning', 'Stripe.subscription.checkout_customer_missing | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ) ) );
     285                peachpay_log(
     286                    'warning',
     287                    'Stripe Subscription checkout customer missing - warning.',
     288                    array(
     289                        'event'     => 'stripe.subscription.checkout_customer_missing',
     290                        'component' => 'payments',
     291                        'feature'   => 'subscription',
     292                        'operation' => 'checkout_customer_missing',
     293                        'outcome'   => 'warning',
     294                        'method'    => __METHOD__,
     295                        'line'      => __LINE__,
     296                        'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ),
     297                    )
     298                );
    249299                $stripe_customer = $this->maybe_create_stripe_customer_for_order( $order, $stripe_mode );
    250300                if ( empty( $stripe_customer ) ) {
    251                     peachpay_log( 'error', 'Stripe.subscription.checkout_customer_resolution_failed | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ) ) );
     301                    peachpay_log(
     302                        'error',
     303                        'Stripe Subscription checkout customer resolution - failed.',
     304                        array(
     305                            'event'     => 'stripe.subscription.checkout_customer_resolution_failed',
     306                            'component' => 'payments',
     307                            'feature'   => 'subscription',
     308                            'operation' => 'checkout_customer_resolution_failed',
     309                            'outcome'   => 'failed',
     310                            'method'    => __METHOD__,
     311                            'line'      => __LINE__,
     312                            'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ),
     313                        )
     314                    );
    252315                }
    253316            }
     
    299362
    300363            if ( ! $result ) {
    301                 peachpay_log( 'error', 'Stripe.checkout.create_payment_returned_null | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ) ) );
     364                peachpay_log(
     365                    'error',
     366                    'Stripe Checkout create payment returned null - failed.',
     367                    array(
     368                        'event'     => 'stripe.checkout.create_payment_returned_null',
     369                        'component' => 'payments',
     370                        'feature'   => 'checkout',
     371                        'operation' => 'create_payment_returned_null',
     372                        'outcome'   => 'failed',
     373                        'method'    => __METHOD__,
     374                        'line'      => __LINE__,
     375                        'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ),
     376                    )
     377                );
    302378                return array(
    303379                    'result'   => 'failed',
     
    344420            );
    345421        } catch ( Exception $exception ) {
    346             peachpay_log( 'error', 'Stripe.checkout.process_payment_exception | ' . json_encode( array( 'order_id' => isset( $order ) && $order instanceof WC_Order ? $order->get_id() : $order_id, 'order_number' => isset( $order ) && $order instanceof WC_Order ? $order->get_order_number() : $order_id, 'error_message' => $exception->getMessage() ) ) );
     422            peachpay_log(
     423                'error',
     424                'Stripe Checkout process payment exception - failed.',
     425                array(
     426                    'event'     => 'stripe.checkout.process_payment_exception',
     427                    'component' => 'payments',
     428                    'feature'   => 'checkout',
     429                    'operation' => 'process_payment_exception',
     430                    'outcome'   => 'failed',
     431                    'method'    => __METHOD__,
     432                    'line'      => __LINE__,
     433                    'data'      => array( 'order_id' => isset( $order ) && $order instanceof WC_Order ? $order->get_id() : $order_id, 'order_number' => isset( $order ) && $order instanceof WC_Order ? $order->get_order_number() : $order_id, 'error_message' => $exception->getMessage() ),
     434                )
     435            );
    347436            $message = __( 'Error: ', 'peachpay-for-woocommerce' ) . $exception->getMessage();
    348437            if ( function_exists( 'wc_add_notice' ) ) {
     
    379468            // Idempotency: do not charge if this renewal order is already paid (prevents double charge from duplicate hooks or webhook + sync race).
    380469            if ( $renewal_order->has_status( array( 'processing', 'completed' ) ) ) {
    381                 peachpay_log( 'debug', 'Stripe: Subscription renewal skipped - order ' . $renewal_order->get_order_number() . ' already paid (status: ' . $renewal_order->get_status() . ').' );
     470                peachpay_log(
     471                    'debug',
     472                    'Stripe Subscription renewal - debug.',
     473                    array(
     474                        'event'     => 'payments.stripe.subscription.renewal.debug',
     475                        'component' => 'payments',
     476                        'feature'   => 'stripe',
     477                        'operation' => 'subscription.renewal',
     478                        'outcome'   => 'debug',
     479                        'method'    => __METHOD__,
     480                        'line'      => __LINE__,
     481                        'data'      => array(
     482                            'details' => 'Stripe: Subscription renewal skipped - order ' . $renewal_order->get_order_number() . ' already paid (status: ' . $renewal_order->get_status() . ').',
     483                        ),
     484                    )
     485                );
    382486                return null;
    383487            }
    384488            if ( ! empty( $renewal_order->get_transaction_id() ) ) {
    385                 peachpay_log( 'debug', 'Stripe: Subscription renewal skipped - order ' . $renewal_order->get_order_number() . ' already has transaction ID.' );
     489                peachpay_log(
     490                    'debug',
     491                    'Stripe Subscription renewal - debug.',
     492                    array(
     493                        'event'     => 'payments.stripe.subscription.renewal.debug',
     494                        'component' => 'payments',
     495                        'feature'   => 'stripe',
     496                        'operation' => 'subscription.renewal',
     497                        'outcome'   => 'debug',
     498                        'method'    => __METHOD__,
     499                        'line'      => __LINE__,
     500                        'data'      => array(
     501                            'details' => 'Stripe: Subscription renewal skipped - order ' . $renewal_order->get_order_number() . ' already has transaction ID.',
     502                        ),
     503                    )
     504                );
    386505                return null;
    387             }
    388 
    389             // If subscription already has another completed renewal order created recently (e.g. duplicate scheduled action), skip to avoid double charge.
    390             if ( function_exists( 'wcs_get_subscriptions_for_renewal_order' ) ) {
    391                 $subscriptions = wcs_get_subscriptions_for_renewal_order( $renewal_order );
    392                 $subscription  = is_array( $subscriptions ) ? array_pop( $subscriptions ) : null;
    393                 if ( $subscription && is_callable( array( $subscription, 'get_related_orders' ) ) ) {
    394                     $renewal_order_ids = $subscription->get_related_orders( 'ids', 'renewal' );
    395                     $recent_cutoff     = strtotime( '-2 hours' );
    396                     foreach ( (array) $renewal_order_ids as $other_id ) {
    397                         if ( (int) $other_id === (int) $renewal_order->get_id() ) {
    398                             continue;
    399                         }
    400                         $other_order = wc_get_order( $other_id );
    401                         if ( ! $other_order || ! $other_order->has_status( array( 'processing', 'completed' ) ) ) {
    402                             continue;
    403                         }
    404                         $created = $other_order->get_date_created();
    405                         if ( $created && $created->getTimestamp() >= $recent_cutoff ) {
    406                             peachpay_log( 'info', 'Stripe: Subscription renewal skipped - subscription already has completed renewal order #' . $other_order->get_order_number() . ' (possible duplicate scheduled action). Order ' . $renewal_order->get_order_number() . ' not charged.' );
    407                             $renewal_order->add_order_note( sprintf(
    408                                 __( 'Renewal payment skipped: subscription already has a completed renewal order #%s. This may be a duplicate; no charge was made.', 'peachpay-for-woocommerce' ),
    409                                 $other_order->get_order_number()
    410                             ) );
    411                             return null;
    412                         }
    413                     }
    414                 }
    415506            }
    416507
     
    423514            if ( empty( $payment_method_id ) ) {
    424515                $message = __( 'Stripe reusable payment method details missing from subscription order.', 'peachpay-for-woocommerce' );
    425                 peachpay_log( 'error', 'Stripe.subscription.renewal_missing_payment_method | ' . json_encode( array( 'parent_order_id' => $parent_order->get_id(), 'parent_order_number' => $parent_order->get_order_number(), 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'stripe_mode' => $stripe_mode ) ) );
     516                peachpay_log(
     517                    'error',
     518                    'Stripe Subscription renewal missing payment method - failed.',
     519                    array(
     520                        'event'     => 'stripe.subscription.renewal_missing_payment_method',
     521                        'component' => 'payments',
     522                        'feature'   => 'subscription',
     523                        'operation' => 'renewal_missing_payment_method',
     524                        'outcome'   => 'failed',
     525                        'method'    => __METHOD__,
     526                        'line'      => __LINE__,
     527                        'data'      => array( 'parent_order_id' => $parent_order->get_id(), 'parent_order_number' => $parent_order->get_order_number(), 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'stripe_mode' => $stripe_mode ),
     528                    )
     529                );
    426530                $renewal_order->update_status( 'failed', $message );
    427531                return null;
     
    430534            if ( empty( $customer_id ) ) {
    431535                $message = __( 'Stripe customer details missing from subscription order.', 'peachpay-for-woocommerce' );
    432                 peachpay_log( 'error', 'Stripe.subscription.renewal_missing_customer | ' . json_encode( array( 'parent_order_id' => $parent_order->get_id(), 'parent_order_number' => $parent_order->get_order_number(), 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'stripe_mode' => $stripe_mode ) ) );
     536                peachpay_log(
     537                    'error',
     538                    'Stripe Subscription renewal missing customer - failed.',
     539                    array(
     540                        'event'     => 'stripe.subscription.renewal_missing_customer',
     541                        'component' => 'payments',
     542                        'feature'   => 'subscription',
     543                        'operation' => 'renewal_missing_customer',
     544                        'outcome'   => 'failed',
     545                        'method'    => __METHOD__,
     546                        'line'      => __LINE__,
     547                        'data'      => array( 'parent_order_id' => $parent_order->get_id(), 'parent_order_number' => $parent_order->get_order_number(), 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'stripe_mode' => $stripe_mode ),
     548                    )
     549                );
    433550                $renewal_order->update_status( 'failed', $message );
    434551                return null;
     
    608725            if ( ! $result['success'] ) {
    609726                return new \WP_Error( 'wc_' . $order_id . '_refund_failed', 'Refund error:' . $result['message'] );
     727            }
     728
     729            if ( ! empty( $result['refund_id'] ) ) {
     730                PeachPay_Stripe::set_pending_wc_refund_id( $order->get_id(), $result['refund_id'] );
    610731            }
    611732
     
    819940    private function maybe_create_stripe_customer_for_order( $order, $stripe_mode ) {
    820941        if ( ! class_exists( 'PeachPay_Stripe_Credentials' ) ) {
    821             peachpay_log( 'error', 'Stripe.subscription.customer_create_missing_credentials_class | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ) ) );
     942            peachpay_log(
     943                'error',
     944                'Stripe Customer create missing credentials class - failed.',
     945                array(
     946                    'event'     => 'stripe.subscription.customer_create_missing_credentials_class',
     947                    'component' => 'payments',
     948                    'feature'   => 'subscription',
     949                    'operation' => 'customer_create_missing_credentials_class',
     950                    'outcome'   => 'failed',
     951                    'method'    => __METHOD__,
     952                    'line'      => __LINE__,
     953                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ),
     954                )
     955            );
    822956            return null;
    823957        }
     
    825959        $stripe = PeachPay_Stripe_Credentials::get_stripe_client( $stripe_mode );
    826960        if ( ! $stripe ) {
    827             peachpay_log( 'error', 'Stripe.subscription.customer_create_missing_client | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ) ) );
     961            peachpay_log(
     962                'error',
     963                'Stripe Customer create missing client - failed.',
     964                array(
     965                    'event'     => 'stripe.subscription.customer_create_missing_client',
     966                    'component' => 'payments',
     967                    'feature'   => 'subscription',
     968                    'operation' => 'customer_create_missing_client',
     969                    'outcome'   => 'failed',
     970                    'method'    => __METHOD__,
     971                    'line'      => __LINE__,
     972                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ),
     973                )
     974            );
    828975            return null;
    829976        }
     
    843990            $customer = $stripe->customers->create( $args );
    844991            if ( ! isset( $customer->id ) || empty( $customer->id ) ) {
    845                 peachpay_log( 'error', 'Stripe.subscription.customer_create_empty_id | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ) ) );
     992                peachpay_log(
     993                    'error',
     994                    'Stripe Customer create empty id - failed.',
     995                    array(
     996                        'event'     => 'stripe.subscription.customer_create_empty_id',
     997                        'component' => 'payments',
     998                        'feature'   => 'subscription',
     999                        'operation' => 'customer_create_empty_id',
     1000                        'outcome'   => 'failed',
     1001                        'method'    => __METHOD__,
     1002                        'line'      => __LINE__,
     1003                        'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode ),
     1004                    )
     1005                );
    8461006                return null;
    8471007            }
     
    8521012            }
    8531013
    854             peachpay_log( 'info', 'Stripe.subscription.customer_created | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'customer_id' => $customer->id, 'user_id' => $user_id, 'stripe_mode' => $stripe_mode ) ) );
     1014            peachpay_log(
     1015                'info',
     1016                'Stripe Customer create - success.',
     1017                array(
     1018                    'event'     => 'stripe.subscription.customer_created',
     1019                    'component' => 'payments',
     1020                    'feature'   => 'subscription',
     1021                    'operation' => 'customer_created',
     1022                    'outcome'   => 'success',
     1023                    'method'    => __METHOD__,
     1024                    'line'      => __LINE__,
     1025                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'customer_id' => $customer->id, 'user_id' => $user_id, 'stripe_mode' => $stripe_mode ),
     1026                )
     1027            );
    8551028            return $customer->id;
    8561029        } catch ( Exception $e ) {
    857             peachpay_log( 'error', 'Stripe.subscription.customer_create_exception | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode, 'error_message' => $e->getMessage() ) ) );
     1030            peachpay_log(
     1031                'error',
     1032                'Stripe Customer create exception - failed.',
     1033                array(
     1034                    'event'     => 'stripe.subscription.customer_create_exception',
     1035                    'component' => 'payments',
     1036                    'feature'   => 'subscription',
     1037                    'operation' => 'customer_create_exception',
     1038                    'outcome'   => 'failed',
     1039                    'method'    => __METHOD__,
     1040                    'line'      => __LINE__,
     1041                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_mode' => $stripe_mode, 'error_message' => $e->getMessage() ),
     1042                )
     1043            );
    8581044            return null;
    8591045        }
     
    8701056        $customer_id = PeachPay_Stripe_Order_Data::get_payment_method( $parent_order, 'customer' );
    8711057        if ( ! empty( $customer_id ) ) {
    872             peachpay_log( 'debug', 'Stripe.subscription.renewal_customer_resolved | ' . json_encode( array( 'parent_order_id' => $parent_order->get_id(), 'parent_order_number' => $parent_order->get_order_number(), 'customer_id' => $customer_id, 'source' => 'payment_method_details', 'peachpay_mode' => $peachpay_mode ) ) );
     1058            peachpay_log(
     1059                'debug',
     1060                'Stripe Subscription renewal customer resolved - debug.',
     1061                array(
     1062                    'event'     => 'stripe.subscription.renewal_customer_resolved',
     1063                    'component' => 'payments',
     1064                    'feature'   => 'subscription',
     1065                    'operation' => 'renewal_customer_resolved',
     1066                    'outcome'   => 'debug',
     1067                    'method'    => __METHOD__,
     1068                    'line'      => __LINE__,
     1069                    'data'      => array( 'parent_order_id' => $parent_order->get_id(), 'parent_order_number' => $parent_order->get_order_number(), 'customer_id' => $customer_id, 'source' => 'payment_method_details', 'peachpay_mode' => $peachpay_mode ),
     1070                )
     1071            );
    8731072            return $customer_id;
    8741073        }
     
    8761075        $customer_id = PeachPay_Stripe_Order_Data::get_payment_intent( $parent_order, 'customer' );
    8771076        if ( ! empty( $customer_id ) ) {
    878             peachpay_log( 'debug', 'Stripe.subscription.renewal_customer_resolved | ' . json_encode( array( 'parent_order_id' => $parent_order->get_id(), 'parent_order_number' => $parent_order->get_order_number(), 'customer_id' => $customer_id, 'source' => 'payment_intent_details', 'peachpay_mode' => $peachpay_mode ) ) );
     1077            peachpay_log(
     1078                'debug',
     1079                'Stripe Subscription renewal customer resolved - debug.',
     1080                array(
     1081                    'event'     => 'stripe.subscription.renewal_customer_resolved',
     1082                    'component' => 'payments',
     1083                    'feature'   => 'subscription',
     1084                    'operation' => 'renewal_customer_resolved',
     1085                    'outcome'   => 'debug',
     1086                    'method'    => __METHOD__,
     1087                    'line'      => __LINE__,
     1088                    'data'      => array( 'parent_order_id' => $parent_order->get_id(), 'parent_order_number' => $parent_order->get_order_number(), 'customer_id' => $customer_id, 'source' => 'payment_intent_details', 'peachpay_mode' => $peachpay_mode ),
     1089                )
     1090            );
    8791091            return $customer_id;
    8801092        }
     
    8841096            $customer_id = PeachPay_Stripe::get_customer( $user_id, $peachpay_mode );
    8851097            if ( ! empty( $customer_id ) ) {
    886                 peachpay_log( 'debug', 'Stripe.subscription.renewal_customer_resolved | ' . json_encode( array( 'parent_order_id' => $parent_order->get_id(), 'parent_order_number' => $parent_order->get_order_number(), 'customer_id' => $customer_id, 'source' => 'user_meta', 'user_id' => $user_id, 'peachpay_mode' => $peachpay_mode ) ) );
     1098                peachpay_log(
     1099                    'debug',
     1100                    'Stripe Subscription renewal customer resolved - debug.',
     1101                    array(
     1102                        'event'     => 'stripe.subscription.renewal_customer_resolved',
     1103                        'component' => 'payments',
     1104                        'feature'   => 'subscription',
     1105                        'operation' => 'renewal_customer_resolved',
     1106                        'outcome'   => 'debug',
     1107                        'method'    => __METHOD__,
     1108                        'line'      => __LINE__,
     1109                        'data'      => array( 'parent_order_id' => $parent_order->get_id(), 'parent_order_number' => $parent_order->get_order_number(), 'customer_id' => $customer_id, 'source' => 'user_meta', 'user_id' => $user_id, 'peachpay_mode' => $peachpay_mode ),
     1110                    )
     1111                );
    8871112                return $customer_id;
    8881113            }
     
    9031128    private function ensure_payment_method_attached_to_customer( $payment_method_id, $customer_id, $stripe_mode, $renewal_order ) {
    9041129        if ( ! class_exists( 'PeachPay_Stripe_Credentials' ) ) {
    905             peachpay_log( 'error', 'Stripe.subscription.renewal_pm_attach_missing_credentials_class | ' . json_encode( array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'customer_id' => $customer_id, 'stripe_mode' => $stripe_mode ) ) );
     1130            peachpay_log(
     1131                'error',
     1132                'Stripe Subscription renewal payment method attach missing credentials class - failed.',
     1133                array(
     1134                    'event'     => 'stripe.subscription.renewal_pm_attach_missing_credentials_class',
     1135                    'component' => 'payments',
     1136                    'feature'   => 'subscription',
     1137                    'operation' => 'renewal_pm_attach_missing_credentials_class',
     1138                    'outcome'   => 'failed',
     1139                    'method'    => __METHOD__,
     1140                    'line'      => __LINE__,
     1141                    'data'      => array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'customer_id' => $customer_id, 'stripe_mode' => $stripe_mode ),
     1142                )
     1143            );
    9061144            return false;
    9071145        }
     
    9091147        $stripe = PeachPay_Stripe_Credentials::get_stripe_client( $stripe_mode );
    9101148        if ( ! $stripe ) {
    911             peachpay_log( 'error', 'Stripe.subscription.renewal_pm_attach_missing_client | ' . json_encode( array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'customer_id' => $customer_id, 'stripe_mode' => $stripe_mode ) ) );
     1149            peachpay_log(
     1150                'error',
     1151                'Stripe Subscription renewal payment method attach missing client - failed.',
     1152                array(
     1153                    'event'     => 'stripe.subscription.renewal_pm_attach_missing_client',
     1154                    'component' => 'payments',
     1155                    'feature'   => 'subscription',
     1156                    'operation' => 'renewal_pm_attach_missing_client',
     1157                    'outcome'   => 'failed',
     1158                    'method'    => __METHOD__,
     1159                    'line'      => __LINE__,
     1160                    'data'      => array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'customer_id' => $customer_id, 'stripe_mode' => $stripe_mode ),
     1161                )
     1162            );
    9121163            return false;
    9131164        }
     
    9221173                    array( 'customer' => $customer_id )
    9231174                );
    924                 peachpay_log( 'info', 'Stripe.subscription.renewal_pm_attached | ' . json_encode( array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'customer_id' => $customer_id, 'stripe_mode' => $stripe_mode ) ) );
     1175                peachpay_log(
     1176                    'info',
     1177                    'Stripe Subscription renewal payment method attached - success.',
     1178                    array(
     1179                        'event'     => 'stripe.subscription.renewal_pm_attached',
     1180                        'component' => 'payments',
     1181                        'feature'   => 'subscription',
     1182                        'operation' => 'renewal_pm_attached',
     1183                        'outcome'   => 'success',
     1184                        'method'    => __METHOD__,
     1185                        'line'      => __LINE__,
     1186                        'data'      => array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'customer_id' => $customer_id, 'stripe_mode' => $stripe_mode ),
     1187                    )
     1188                );
    9251189                return true;
    9261190            }
    9271191
    9281192            if ( $attached_to !== $customer_id ) {
    929                 peachpay_log( 'error', 'Stripe.subscription.renewal_pm_attached_to_different_customer | ' . json_encode( array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'expected_customer_id' => $customer_id, 'actual_customer_id' => $attached_to, 'stripe_mode' => $stripe_mode ) ) );
     1193                peachpay_log(
     1194                    'error',
     1195                    'Stripe Subscription renewal payment method attached to different customer - failed.',
     1196                    array(
     1197                        'event'     => 'stripe.subscription.renewal_pm_attached_to_different_customer',
     1198                        'component' => 'payments',
     1199                        'feature'   => 'subscription',
     1200                        'operation' => 'renewal_pm_attached_to_different_customer',
     1201                        'outcome'   => 'failed',
     1202                        'method'    => __METHOD__,
     1203                        'line'      => __LINE__,
     1204                        'data'      => array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'expected_customer_id' => $customer_id, 'actual_customer_id' => $attached_to, 'stripe_mode' => $stripe_mode ),
     1205                    )
     1206                );
    9301207                return false;
    9311208            }
    9321209
    933             peachpay_log( 'debug', 'Stripe.subscription.renewal_pm_already_attached | ' . json_encode( array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'customer_id' => $customer_id, 'stripe_mode' => $stripe_mode ) ) );
     1210            peachpay_log(
     1211                'debug',
     1212                'Stripe Subscription renewal payment method already attached - debug.',
     1213                array(
     1214                    'event'     => 'stripe.subscription.renewal_pm_already_attached',
     1215                    'component' => 'payments',
     1216                    'feature'   => 'subscription',
     1217                    'operation' => 'renewal_pm_already_attached',
     1218                    'outcome'   => 'debug',
     1219                    'method'    => __METHOD__,
     1220                    'line'      => __LINE__,
     1221                    'data'      => array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'customer_id' => $customer_id, 'stripe_mode' => $stripe_mode ),
     1222                )
     1223            );
    9341224            return true;
    9351225        } catch ( Exception $e ) {
    936             peachpay_log( 'error', 'Stripe.subscription.renewal_pm_attach_exception | ' . json_encode( array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'customer_id' => $customer_id, 'stripe_mode' => $stripe_mode, 'error_message' => $e->getMessage() ) ) );
     1226            peachpay_log(
     1227                'error',
     1228                'Stripe Subscription renewal payment method attach exception - failed.',
     1229                array(
     1230                    'event'     => 'stripe.subscription.renewal_pm_attach_exception',
     1231                    'component' => 'payments',
     1232                    'feature'   => 'subscription',
     1233                    'operation' => 'renewal_pm_attach_exception',
     1234                    'outcome'   => 'failed',
     1235                    'method'    => __METHOD__,
     1236                    'line'      => __LINE__,
     1237                    'data'      => array( 'renewal_order_id' => $renewal_order->get_id(), 'renewal_order_number' => $renewal_order->get_order_number(), 'payment_method_id' => $payment_method_id, 'customer_id' => $customer_id, 'stripe_mode' => $stripe_mode, 'error_message' => $e->getMessage() ),
     1238                )
     1239            );
    9371240            return false;
    9381241        }
  • peachpay-for-woocommerce/trunk/core/payments/stripe/functions.php

    r3485577 r3490786  
    186186
    187187/**
     188 * Links a WooCommerce refund record to a Stripe refund ID for admin-initiated refunds.
     189 *
     190 * @param int   $refund_id WooCommerce refund ID.
     191 * @param array $args Refund creation arguments.
     192 */
     193function peachpay_stripe_handle_wc_refund_created( $refund_id, $args ) {
     194    if ( empty( $args['refund_payment'] ) || empty( $args['order_id'] ) ) {
     195        return;
     196    }
     197
     198    $order = wc_get_order( $args['order_id'] );
     199    if ( ! $order || ! PeachPay_Stripe_Integration::is_payment_gateway( $order->get_payment_method() ) ) {
     200        return;
     201    }
     202
     203    if ( ! class_exists( 'PeachPay_Stripe' ) || ! method_exists( 'PeachPay_Stripe', 'consume_pending_wc_refund_id' ) ) {
     204        return;
     205    }
     206
     207    $stripe_refund_id = PeachPay_Stripe::consume_pending_wc_refund_id( $order->get_id() );
     208    if ( empty( $stripe_refund_id ) ) {
     209        return;
     210    }
     211
     212    $refund = wc_get_order( $refund_id );
     213    if ( ! $refund || ! is_a( $refund, 'WC_Order_Refund' ) ) {
     214        return;
     215    }
     216
     217    $refund->update_meta_data( '_pp_stripe_refund_id', $stripe_refund_id );
     218    $refund->save();
     219}
     220
     221/**
    188222 * Captures the payment if the order payment was authorized and not captured immediately.
    189223 *
  • peachpay-for-woocommerce/trunk/core/payments/stripe/hooks.php

    r3485577 r3490786  
    2727add_action( 'woocommerce_order_status_cancelled', 'peachpay_stripe_handle_order_cancelled', 10, 1 );
    2828add_action( 'woocommerce_order_status_changed', 'peachpay_stripe_handle_order_processing', 10, 4 );
     29add_action( 'woocommerce_refund_created', 'peachpay_stripe_handle_wc_refund_created', 10, 2 );
    2930
    3031// Public ajax routes
  • peachpay-for-woocommerce/trunk/core/payments/stripe/routes/stripe-webhook.php

    r3485577 r3490786  
    3434            $event = \Stripe\Webhook::constructEvent( $payload, $sig_header, $webhook_secret );
    3535        } catch ( \UnexpectedValueException $e ) {
    36             peachpay_log( 'error', 'Stripe.webhook.invalid_payload | ' . json_encode( array( 'error_message' => $e->getMessage() ) ) );
     36            peachpay_log(
     37                'error',
     38                'Stripe Webhook invalid payload - failed.',
     39                array(
     40                    'event'     => 'stripe.webhook.invalid_payload',
     41                    'component' => 'webhooks',
     42                    'feature'   => 'stripe',
     43                    'operation' => 'invalid_payload',
     44                    'outcome'   => 'failed',
     45                    'method'    => __METHOD__,
     46                    'line'      => __LINE__,
     47                    'data'      => array( 'error_message' => $e->getMessage() ),
     48                )
     49            );
    3750            wp_send_json_error( 'Invalid payload', 400 );
    3851            return;
    3952        } catch ( \Stripe\Exception\SignatureVerificationException $e ) {
    40             peachpay_log( 'error', 'Stripe.webhook.invalid_signature | ' . json_encode( array( 'error_message' => $e->getMessage() ) ) );
     53            peachpay_log(
     54                'error',
     55                'Stripe Webhook invalid signature - failed.',
     56                array(
     57                    'event'     => 'stripe.webhook.invalid_signature',
     58                    'component' => 'webhooks',
     59                    'feature'   => 'stripe',
     60                    'operation' => 'invalid_signature',
     61                    'outcome'   => 'failed',
     62                    'method'    => __METHOD__,
     63                    'line'      => __LINE__,
     64                    'data'      => array( 'error_message' => $e->getMessage() ),
     65                )
     66            );
    4167            wp_send_json_error( 'Invalid signature', 400 );
    4268            return;
    4369        }
    4470
    45         peachpay_log( 'debug', 'Stripe.webhook.verified_event_received | ' . json_encode( array( 'event_type' => $event->type, 'event_id' => $event->id ) ) );
    46         // Process the verified event.
    47         return peachpay_process_stripe_webhook_event( $event );
     71        $site_mode = ! peachpay_is_test_mode();
     72        if ( isset( $event->livemode ) && (bool) $event->livemode !== (bool) $site_mode ) {
     73            peachpay_log(
     74                'warning',
     75                'Stripe Webhook mode mismatch: The recieved Stripe event was ignored because its mode (live/test) does not match the current PeachPay site mode. This helps ensure events are processed only in the appropriate environment and prevents accidental cross-environment actions.',
     76                array(
     77                    'event'     => 'stripe.webhook.mode_mismatch',
     78                    'component' => 'webhooks',
     79                    'feature'   => 'stripe',
     80                    'operation' => 'mode_validation',
     81                    'outcome'   => 'ignored',
     82                    'method'    => __METHOD__,
     83                    'line'      => __LINE__,
     84                    'data'      => array(
     85                        'event_livemode' => (bool) $event->livemode,
     86                        'site_mode'      => (bool) $site_mode,
     87                        'event_id'       => ! empty( $event->id ) ? (string) $event->id : '',
     88                    ),
     89                )
     90            );
     91            wp_send_json_success(
     92                array(
     93                    'ignored'         => true,
     94                    'message'         => sprintf(
     95                        'The Stripe event was not processed because its mode (%s) did not match the current PeachPay site mode (%s). No action taken.',
     96                        (isset($event->livemode) && $event->livemode) ? 'live' : 'test',
     97                        $site_mode ? 'live' : 'test'
     98                    ),
     99                    'webhook_mode'    => (isset($event->livemode) && $event->livemode) ? 'live' : 'test',
     100                    'current_mode'    => $site_mode ? 'live' : 'test',
     101                )
     102            );
     103            return;
     104        }
     105
     106
     107        $event_id       = ! empty( $event->id ) ? (string) $event->id : '';
     108        $transient_key  = '';
     109        if ( '' !== $event_id ) {
     110            $transient_key = 'pp_stripe_event_' . $event_id;
     111            if ( false !== get_transient( $transient_key ) ) {
     112                peachpay_log(
     113                    'debug',
     114                    'Stripe Webhook duplicate event skipped - event type: ' . $event->type . ' event id: ' . $event_id,
     115                    array(
     116                        'event'     => 'stripe.webhook.duplicate_event_skipped',
     117                        'component' => 'webhooks',
     118                        'feature'   => 'stripe',
     119                        'operation' => 'duplicate_event_skipped',
     120                        'outcome'   => 'debug',
     121                        'method'    => __METHOD__,
     122                        'line'      => __LINE__,
     123                        'data'      => array(
     124                            'payload'  => json_decode($payload, true)
     125                        ),
     126                    )
     127                );
     128                wp_send_json_error(
     129                    array(
     130                        'received'  => true,
     131                        'duplicate' => true,
     132                    )
     133                );
     134                return;
     135            }
     136
     137            set_transient( $transient_key, true, DAY_IN_SECONDS );
     138        }
     139
     140        try {
     141            peachpay_log(
     142                'debug',
     143                'Stripe Webhook verified event received - event type: ' . $event->type . ' event id: ' . $event->id,
     144                array(
     145                    'event'     => 'stripe.webhook.verified_event_received',
     146                    'component' => 'webhooks',
     147                    'feature'   => 'stripe',
     148                    'operation' => 'verified_event_received',
     149                    'outcome'   => 'debug',
     150                    'method'    => __METHOD__,
     151                    'line'      => __LINE__,
     152                    'data'      => array(
     153                        'payload'  => json_decode($payload, true)
     154                    ),
     155                )
     156            );
     157            // Process the verified event.
     158            return peachpay_process_stripe_webhook_event( $event );
     159        } catch ( \Throwable $e ) {
     160            if ( '' !== $transient_key ) {
     161                delete_transient( $transient_key );
     162            }
     163
     164            peachpay_log(
     165                'error',
     166                'Stripe Webhook processing failed - transient released for retry.',
     167                array(
     168                    'event'     => 'stripe.webhook.processing_failed',
     169                    'component' => 'webhooks',
     170                    'feature'   => 'stripe',
     171                    'operation' => 'processing_failed',
     172                    'outcome'   => 'failed',
     173                    'method'    => __METHOD__,
     174                    'line'      => __LINE__,
     175                    'data'      => array(
     176                        'event_id'      => $event_id,
     177                        'event_type'    => $event->type ?? '',
     178                        'error_message' => $e->getMessage(),
     179                    ),
     180                )
     181            );
     182
     183            wp_send_json_error(
     184                array(
     185                    'received' => false,
     186                    'error'    => 'Webhook processing failed',
     187                ),
     188                500
     189            );
     190            return;
     191        }
    48192    }
    49193
    50194    // Fallback: Handle legacy webhook format (from PeachPay server proxy).
    51195    // This maintains backward compatibility during transition.
    52     $order = wc_get_order( $request['order_id'] );
    53196    $params    = $request instanceof WP_REST_Request ? $request->get_params() : (array) $request;
    54197    $order_id  = $params['order_id'] ?? null;
    55198    $event_type = $params['type'] ?? 'unknown';
    56199
    57     peachpay_log( 'info', 'Stripe.webhook.legacy_event_received | ' . json_encode( array( 'event_type' => $event_type, 'order_id' => $order_id ) ) );
     200    peachpay_log(
     201        'info',
     202        'Stripe Webhook legacy event received - success.',
     203        array(
     204            'event'     => 'stripe.webhook.legacy_event_received',
     205            'component' => 'webhooks',
     206            'feature'   => 'stripe',
     207            'operation' => 'legacy_event_received',
     208            'outcome'   => 'success',
     209            'method'    => __METHOD__,
     210            'line'      => __LINE__,
     211            'data'      => array( 'event_type' => $event_type, 'order_id' => $order_id ),
     212        )
     213    );
    58214
    59215    $order = wc_get_order( $order_id );
    60216    if ( ! $order ) {
    61         peachpay_log( 'error', 'Stripe.webhook.legacy_order_not_found | ' . json_encode( array( 'order_id' => $order_id ) ) );
     217        peachpay_log(
     218            'error',
     219            'Stripe Webhook legacy order not found - failed.',
     220            array(
     221                'event'     => 'stripe.webhook.legacy_order_not_found',
     222                'component' => 'webhooks',
     223                'feature'   => 'stripe',
     224                'operation' => 'legacy_order_not_found',
     225                'outcome'   => 'failed',
     226                'method'    => __METHOD__,
     227                'line'      => __LINE__,
     228                'data'      => array( 'order_id' => $order_id ),
     229            )
     230        );
    62231        wp_send_json_error( 'Required field "order_id" was invalid or missing', 400 );
    63232        return;
     
    93262    $type = $event->type;
    94263    $data = $event->data->object;
    95 
    96     peachpay_log( 'debug', 'Stripe.webhook.processing_event | ' . json_encode( array( 'event_type' => $type ) ) );
     264    $livemode = $event->livemode;
     265
     266    peachpay_log(
     267        'debug',
     268        'Stripe Webhook processing event - debug.',
     269        array(
     270            'event'     => 'stripe.webhook.processing_event',
     271            'component' => 'webhooks',
     272            'feature'   => 'stripe',
     273            'operation' => 'processing_event',
     274            'outcome'   => 'debug',
     275            'method'    => __METHOD__,
     276            'line'      => __LINE__,
     277            'data'      => array( 'event_type' => $type ),
     278        )
     279    );
    97280    switch ( $type ) {
    98281        case 'payment_intent.succeeded':
    99             peachpay_handle_payment_intent_webhook( $data, 'succeeded' );
     282            peachpay_handle_payment_intent_webhook( $data, 'succeeded' , $livemode);
    100283            break;
    101284
    102285        case 'payment_intent.payment_failed':
    103             peachpay_handle_payment_intent_webhook( $data, 'failed' );
     286            peachpay_handle_payment_intent_webhook( $data, 'failed' , $livemode);
    104287            break;
    105288
    106289        case 'payment_intent.canceled':
    107             peachpay_handle_payment_intent_webhook( $data, 'canceled' );
     290            peachpay_handle_payment_intent_webhook( $data, 'canceled' , $livemode);
    108291            break;
    109292
    110293        case 'payment_intent.requires_action':
    111             peachpay_handle_payment_intent_webhook( $data, 'requires_action' );
     294            peachpay_handle_payment_intent_webhook( $data, 'requires_action' , $livemode);
    112295            break;
    113296
    114297        case 'payment_intent.processing':
    115             peachpay_handle_payment_intent_webhook( $data, 'processing' );
     298            peachpay_handle_payment_intent_webhook( $data, 'processing' , $livemode);
    116299            break;
    117300
     
    130313        default:
    131314            // Unhandled event type - just acknowledge receipt.
    132             peachpay_log( 'debug', 'Stripe.webhook.unhandled_event | ' . json_encode( array( 'event_type' => $type ) ) );
     315            peachpay_log(
     316                'debug',
     317                'Stripe Webhook unhandled event - debug.',
     318                array(
     319                    'event'     => 'stripe.webhook.unhandled_event',
     320                    'component' => 'webhooks',
     321                    'feature'   => 'stripe',
     322                    'operation' => 'unhandled_event',
     323                    'outcome'   => 'debug',
     324                    'method'    => __METHOD__,
     325                    'line'      => __LINE__,
     326                    'data'      => array( 'event_type' => $type ),
     327                )
     328            );
    133329            break;
    134330    }
     
    143339 * @param string $status The status type.
    144340 */
    145 function peachpay_handle_payment_intent_webhook( $payment_intent, $status ) {
     341function peachpay_handle_payment_intent_webhook( $payment_intent, $status, $livemode = false ) {
    146342    // Find the order by payment intent ID.
    147343    $order = peachpay_find_order_by_payment_intent( $payment_intent->id );
    148344
    149345    if ( ! $order ) {
    150         peachpay_log( 'debug', 'Stripe.webhook.payment_intent_order_not_found | ' . json_encode( array( 'payment_intent_id' => $payment_intent->id, 'event_status' => $status ) ) );
     346        peachpay_log(
     347            'debug',
     348            'Stripe Webhook payment intent order not found - debug.',
     349            array(
     350                'event'     => 'stripe.webhook.payment_intent_order_not_found',
     351                'component' => 'webhooks',
     352                'feature'   => 'stripe',
     353                'operation' => 'payment_intent_order_not_found',
     354                'outcome'   => 'debug',
     355                'method'    => __METHOD__,
     356                'line'      => __LINE__,
     357                'data'      => array( 'payment_intent_id' => $payment_intent->id, 'event_status' => $status ),
     358            )
     359        );
    151360        return;
    152361    }
    153362
    154     peachpay_log( 'info', 'Stripe.webhook.payment_intent_event | ' . json_encode( array( 'event_status' => $status, 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'payment_intent_id' => $payment_intent->id ) ) );
     363    peachpay_log(
     364        'info',
     365        'Stripe Webhook payment intent event - success.',
     366        array(
     367            'event'     => 'stripe.webhook.payment_intent_event',
     368            'component' => 'webhooks',
     369            'feature'   => 'stripe',
     370            'operation' => 'payment_intent_event',
     371            'outcome'   => 'success',
     372            'method'    => __METHOD__,
     373            'line'      => __LINE__,
     374            'data'      => array( 'event_status' => $status, 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'payment_intent_id' => $payment_intent->id ),
     375        )
     376    );
    155377    $payment_details = array(
    156378        'payment_intent_details' => array(
     
    160382            'amount_capturable' => $payment_intent->amount_capturable ?? 0,
    161383            'currency'          => $payment_intent->currency,
    162             'mode'              => 'live' === substr( $payment_intent->id, 3, 4 ) ? 'live' : 'test',
     384            'mode'              => $livemode ? 'live' : 'test',
    163385        ),
    164386    );
     
    182404                );
    183405            } catch ( \Exception $e ) {
    184                 peachpay_log( 'debug', 'Stripe.webhook.payment_intent_charge_retrieve_failed | ' . json_encode( array( 'payment_intent_id' => $payment_intent->id, 'error_message' => $e->getMessage() ) ) );
     406                peachpay_log(
     407                    'debug',
     408                    'Stripe Webhook payment intent charge retrieve failed - debug.',
     409                    array(
     410                        'event'     => 'stripe.webhook.payment_intent_charge_retrieve_failed',
     411                        'component' => 'webhooks',
     412                        'feature'   => 'stripe',
     413                        'operation' => 'payment_intent_charge_retrieve_failed',
     414                        'outcome'   => 'debug',
     415                        'method'    => __METHOD__,
     416                        'line'      => __LINE__,
     417                        'data'      => array( 'payment_intent_id' => $payment_intent->id, 'error_message' => $e->getMessage() ),
     418                    )
     419                );
    185420            }
    186421        }
     
    211446
    212447    if ( ! $order ) {
    213         peachpay_log( 'debug', 'Stripe.webhook.charge_refunded_order_not_found | ' . json_encode( array( 'charge_id' => $charge->id ) ) );
     448        peachpay_log(
     449            'debug',
     450            'Stripe Webhook charge refunded order not found - debug.',
     451            array(
     452                'event'     => 'stripe.webhook.charge_refunded_order_not_found',
     453                'component' => 'webhooks',
     454                'feature'   => 'stripe',
     455                'operation' => 'charge_refunded_order_not_found',
     456                'outcome'   => 'debug',
     457                'method'    => __METHOD__,
     458                'line'      => __LINE__,
     459                'data'      => array( 'charge_id' => $charge->id ),
     460            )
     461        );
    214462        return;
    215463    }
    216464
    217     peachpay_log( 'info', 'Stripe.webhook.charge_refunded_event | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'charge_id' => $charge->id ) ) );
     465    peachpay_log(
     466        'info',
     467        'Stripe Webhook charge refunded event - success.',
     468        array(
     469            'event'     => 'stripe.webhook.charge_refunded_event',
     470            'component' => 'webhooks',
     471            'feature'   => 'stripe',
     472            'operation' => 'charge_refunded_event',
     473            'outcome'   => 'success',
     474            'method'    => __METHOD__,
     475            'line'      => __LINE__,
     476            'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'charge_id' => $charge->id ),
     477        )
     478    );
    218479    $payment_details = array(
    219480        'charge_details' => array(
     
    253514function peachpay_sync_wc_refunds_from_stripe_charge( $order, $charge ) {
    254515    if ( empty( $charge->refunds ) || empty( $charge->refunds->data ) ) {
    255         peachpay_log( 'debug', 'Stripe.webhook.charge_refunded_no_refund_entries | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'charge_id' => $charge->id ) ) );
     516        peachpay_log(
     517            'debug',
     518            'Stripe Webhook charge refunded no refund entries - debug.',
     519            array(
     520                'event'     => 'stripe.webhook.charge_refunded_no_refund_entries',
     521                'component' => 'webhooks',
     522                'feature'   => 'stripe',
     523                'operation' => 'charge_refunded_no_refund_entries',
     524                'outcome'   => 'debug',
     525                'method'    => __METHOD__,
     526                'line'      => __LINE__,
     527                'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'charge_id' => $charge->id ),
     528            )
     529        );
    256530        return;
    257531    }
     
    263537        }
    264538
    265         $existing_refund = peachpay_find_wc_refund_by_stripe_refund_id( $order, $refund->id );
     539        $existing_refund = peachpay_find_wc_refund_by_stripe_refund_id( $order, $refund->id, $refund->amount ?? null, $refund->currency ?? null );
    266540        if ( $existing_refund ) {
     541            peachpay_log(
     542                'debug',
     543                'Stripe.webhook.refund_already_processed',
     544                array(
     545                    'stripe_refund_id' => $refund->id,
     546                    'order_id' => $order->get_id(),
     547                )
     548            );
     549       
    267550            continue;
    268551        }
     
    279562
    280563        if ( is_wp_error( $wc_refund ) ) {
    281             peachpay_log( 'error', 'Stripe.webhook.refund_sync_create_wc_refund_failed | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_refund_id' => $refund->id, 'error_message' => $wc_refund->get_error_message() ) ) );
     564            peachpay_log(
     565                'error',
     566                'Stripe Webhook refund sync create WC refund failed - failed.',
     567                array(
     568                    'event'     => 'stripe.webhook.refund_sync_create_wc_refund_failed',
     569                    'component' => 'webhooks',
     570                    'feature'   => 'stripe',
     571                    'operation' => 'refund_sync_create_wc_refund_failed',
     572                    'outcome'   => 'failed',
     573                    'method'    => __METHOD__,
     574                    'line'      => __LINE__,
     575                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'stripe_refund_id' => $refund->id, 'error_message' => $wc_refund->get_error_message() ),
     576                )
     577            );
    282578            continue;
    283579        }
     
    287583        $created_count++;
    288584
    289         peachpay_log( 'info', 'Stripe.webhook.refund_sync_created_wc_refund | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'wc_refund_id' => $wc_refund->get_id(), 'stripe_refund_id' => $refund->id, 'refund_amount' => $refund_amount, 'currency' => $currency ) ) );
     585        peachpay_log(
     586            'info',
     587            'Stripe Webhook refund sync created WC refund - success.',
     588            array(
     589                'event'     => 'stripe.webhook.refund_sync_created_wc_refund',
     590                'component' => 'webhooks',
     591                'feature'   => 'stripe',
     592                'operation' => 'refund_sync_created_wc_refund',
     593                'outcome'   => 'success',
     594                'method'    => __METHOD__,
     595                'line'      => __LINE__,
     596                'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'wc_refund_id' => $wc_refund->get_id(), 'stripe_refund_id' => $refund->id, 'refund_amount' => $refund_amount, 'currency' => $currency ),
     597            )
     598        );
    290599    }
    291600
     
    311620 * Finds an existing WooCommerce refund by Stripe refund id.
    312621 *
     622 * @param WC_Order       $order The WooCommerce order.
     623 * @param string         $stripe_refund_id The Stripe refund id.
     624 * @param int|float|null $stripe_refund_amount Stripe refund amount in Stripe smallest unit.
     625 * @param string|null    $stripe_refund_currency Stripe refund currency code.
     626 * @return WC_Order_Refund|false
     627 */
     628function peachpay_find_wc_refund_by_stripe_refund_id( $order, $stripe_refund_id, $stripe_refund_amount = null, $stripe_refund_currency = null ) {
     629    $order_refunds = $order->get_refunds();
     630
     631    // Primary idempotency key: exact Stripe refund id.
     632    foreach ( $order_refunds as $refund ) {
     633        if ( $stripe_refund_id === $refund->get_meta( '_pp_stripe_refund_id', true ) ) {
     634            return $refund;
     635        }
     636    }
     637
     638    // Secondary check: some installs may already store the Stripe refund id in refund reason.
     639    foreach ( $order_refunds as $refund ) {
     640        $reason = (string) $refund->get_reason();
     641        if ( '' !== $reason && false !== strpos( $reason, $stripe_refund_id ) ) {
     642            $refund->update_meta_data( '_pp_stripe_refund_id', $stripe_refund_id );
     643            $refund->save();
     644            return $refund;
     645        }
     646    }
     647
     648    // Webhook-only fallback for Woo-admin initiated refunds:
     649    // if order notes already reference this Stripe refund id, attach it to a likely matching recent Woo refund.
     650    if ( ! is_numeric( $stripe_refund_amount ) || ! peachpay_order_has_stripe_refund_note( $order, $stripe_refund_id ) ) {
     651        return false;
     652    }
     653
     654    $currency              = strtoupper( $stripe_refund_currency ?? $order->get_currency() );
     655    $expected_refund_total = (float) PeachPay_Stripe::display_amount( $stripe_refund_amount, $currency );
     656
     657    foreach ( $order->get_refunds() as $refund ) {
     658        $refund_total = abs( (float) $refund->get_amount() );
     659        if ( abs( $refund_total - $expected_refund_total ) >= 0.01 ) {
     660            continue;
     661        }
     662
     663        $created_at = $refund->get_date_created();
     664        if ( ! $created_at || ( time() - $created_at->getTimestamp() ) > 3600 ) {
     665            continue;
     666        }
     667
     668        $refund->update_meta_data( '_pp_stripe_refund_id', $stripe_refund_id );
     669        $refund->save();
     670        return $refund;
     671    }
     672
     673    return false;
     674}
     675
     676/**
     677 * Checks whether an order note already references a Stripe refund id.
     678 *
    313679 * @param WC_Order $order The WooCommerce order.
    314680 * @param string   $stripe_refund_id The Stripe refund id.
    315  * @return WC_Order_Refund|false
    316  */
    317 function peachpay_find_wc_refund_by_stripe_refund_id( $order, $stripe_refund_id ) {
    318     foreach ( $order->get_refunds() as $refund ) {
    319         if ( $stripe_refund_id === $refund->get_meta( '_pp_stripe_refund_id', true ) ) {
    320             return $refund;
     681 * @return bool
     682 */
     683function peachpay_order_has_stripe_refund_note( $order, $stripe_refund_id ) {
     684    if ( empty( $stripe_refund_id ) ) {
     685        return false;
     686    }
     687
     688    $order_notes = wc_get_order_notes(
     689        array(
     690            'order_id' => $order->get_id(),
     691            'limit'    => 20,
     692            'orderby'  => 'date_created',
     693            'order'    => 'DESC',
     694        )
     695    );
     696
     697    foreach ( $order_notes as $note ) {
     698        if ( isset( $note->content ) && false !== strpos( (string) $note->content, $stripe_refund_id ) ) {
     699            return true;
    321700        }
    322701    }
     
    336715
    337716    if ( ! $order ) {
    338         peachpay_log( 'debug', 'Stripe.webhook.dispute_order_not_found | ' . json_encode( array( 'action' => $action, 'charge_id' => $charge_id ) ) );
     717        peachpay_log(
     718            'debug',
     719            'Stripe Webhook dispute order not found - debug.',
     720            array(
     721                'event'     => 'stripe.webhook.dispute_order_not_found',
     722                'component' => 'webhooks',
     723                'feature'   => 'stripe',
     724                'operation' => 'dispute_order_not_found',
     725                'outcome'   => 'debug',
     726                'method'    => __METHOD__,
     727                'line'      => __LINE__,
     728                'data'      => array( 'action' => $action, 'charge_id' => $charge_id ),
     729            )
     730        );
    339731        return;
    340732    }
    341733
    342     peachpay_log( 'info', 'Stripe.webhook.dispute_event | ' . json_encode( array( 'action' => $action, 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'charge_id' => $charge_id, 'dispute_id' => $dispute->id ) ) );
     734    peachpay_log(
     735        'info',
     736        'Stripe Webhook dispute event - success.',
     737        array(
     738            'event'     => 'stripe.webhook.dispute_event',
     739            'component' => 'webhooks',
     740            'feature'   => 'stripe',
     741            'operation' => 'dispute_event',
     742            'outcome'   => 'success',
     743            'method'    => __METHOD__,
     744            'line'      => __LINE__,
     745            'data'      => array( 'action' => $action, 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'charge_id' => $charge_id, 'dispute_id' => $dispute->id ),
     746        )
     747    );
    343748    $dispute_details = array(
    344749        'type'       => 'charge.dispute.' . $action,
  • peachpay-for-woocommerce/trunk/core/payments/stripe/utils/class-peachpay-stripe.php

    r3485577 r3490786  
    176176
    177177    /**
     178     * In-request map of pending Stripe refund IDs keyed by WooCommerce order ID.
     179     *
     180     * Used to link Woo refund records to Stripe refund IDs during admin-initiated refunds.
     181     *
     182     * @var array<int,string>
     183     */
     184    private static $pending_wc_refund_ids = array();
     185
     186    /**
     187     * Stores a pending Stripe refund ID for a WooCommerce order in the current request.
     188     *
     189     * @param int    $order_id WooCommerce order ID.
     190     * @param string $refund_id Stripe refund ID.
     191     */
     192    public static function set_pending_wc_refund_id( $order_id, $refund_id ) {
     193        $order_id  = absint( $order_id );
     194        $refund_id = is_string( $refund_id ) ? trim( $refund_id ) : '';
     195
     196        if ( 0 === $order_id || '' === $refund_id ) {
     197            return;
     198        }
     199
     200        self::$pending_wc_refund_ids[ $order_id ] = $refund_id;
     201    }
     202
     203    /**
     204     * Gets and clears a pending Stripe refund ID for a WooCommerce order.
     205     *
     206     * @param int $order_id WooCommerce order ID.
     207     * @return string|null
     208     */
     209    public static function consume_pending_wc_refund_id( $order_id ) {
     210        $order_id = absint( $order_id );
     211        if ( 0 === $order_id || ! isset( self::$pending_wc_refund_ids[ $order_id ] ) ) {
     212            return null;
     213        }
     214
     215        $refund_id = self::$pending_wc_refund_ids[ $order_id ];
     216        unset( self::$pending_wc_refund_ids[ $order_id ] );
     217
     218        return $refund_id;
     219    }
     220
     221    /**
    178222     * Formats a stripe amount for displaying to merchants/customers.
    179223     *
     
    264308     */
    265309    public static function create_payment( $order, $payment_intent_params, $order_details, $mode ) {
    266         peachpay_log( 'debug', 'Stripe.payment_intent.create.request | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'mode' => $mode ) ) );
     310        peachpay_log(
     311            'debug',
     312            'Stripe Payment intent create request - debug.',
     313            array(
     314                'event'     => 'stripe.payment_intent.create.request',
     315                'component' => 'payments',
     316                'feature'   => 'payment_intent',
     317                'operation' => 'create.request',
     318                'outcome'   => 'debug',
     319                'method'    => __METHOD__,
     320                'line'      => __LINE__,
     321                'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'mode' => $mode ),
     322            )
     323        );
    267324
    268325        try {
     
    270327
    271328            if ( ! $stripe ) {
    272                 peachpay_log( 'error', 'Stripe.payment_intent.create.not_configured | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'mode' => $mode ) ) );
     329                peachpay_log(
     330                    'error',
     331                    'Stripe Payment intent create not configured - failed.',
     332                    array(
     333                        'event'     => 'stripe.payment_intent.create.not_configured',
     334                        'component' => 'payments',
     335                        'feature'   => 'payment_intent',
     336                        'operation' => 'create.not_configured',
     337                        'outcome'   => 'failed',
     338                        'method'    => __METHOD__,
     339                        'line'      => __LINE__,
     340                        'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'mode' => $mode ),
     341                    )
     342                );
    273343                $order->update_status( 'failed', __( 'Stripe is not configured. Please add your API keys.', 'peachpay-for-woocommerce' ) );
    274344                return null;
     
    333403            self::calculate_payment_state( $order, $payment_details );
    334404
    335             peachpay_log( 'info', 'Stripe.payment_intent.create.success | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'payment_intent_id' => $payment_intent->id, 'status' => $payment_intent->status, 'mode' => $mode ) ) );
     405            peachpay_log(
     406                'info',
     407                'Stripe Payment intent create - success.',
     408                array(
     409                    'event'     => 'stripe.payment_intent.create.success',
     410                    'component' => 'payments',
     411                    'feature'   => 'payment_intent',
     412                    'operation' => 'create',
     413                    'outcome'   => 'success',
     414                    'method'    => __METHOD__,
     415                    'line'      => __LINE__,
     416                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'payment_intent_id' => $payment_intent->id, 'status' => $payment_intent->status, 'mode' => $mode ),
     417                )
     418            );
    336419            return $payment_details['payment_intent_details'];
    337420
    338421        } catch ( \Stripe\Exception\CardException $e ) {
    339422            $error_message = $e->getMessage();
    340             peachpay_log( 'error', 'Stripe.payment_intent.create.card_exception | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $error_message, 'mode' => $mode ) ) );
     423            peachpay_log(
     424                'error',
     425                'Stripe Payment intent create card exception - failed.',
     426                array(
     427                    'event'     => 'stripe.payment_intent.create.card_exception',
     428                    'component' => 'payments',
     429                    'feature'   => 'payment_intent',
     430                    'operation' => 'create.card_exception',
     431                    'outcome'   => 'failed',
     432                    'method'    => __METHOD__,
     433                    'line'      => __LINE__,
     434                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $error_message, 'mode' => $mode ),
     435                )
     436            );
    341437            if ( function_exists( 'wc_add_notice' ) ) {
    342438                wc_add_notice( __( 'Payment error: ', 'peachpay-for-woocommerce' ) . $error_message, 'error' );
     
    350446        } catch ( \Stripe\Exception\ApiErrorException $e ) {
    351447            $error_message = $e->getMessage();
    352             peachpay_log( 'error', 'Stripe.payment_intent.create.api_exception | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $error_message, 'mode' => $mode ) ) );
     448            peachpay_log(
     449                'error',
     450                'Stripe Payment intent create API exception - failed.',
     451                array(
     452                    'event'     => 'stripe.payment_intent.create.api_exception',
     453                    'component' => 'payments',
     454                    'feature'   => 'payment_intent',
     455                    'operation' => 'create.api_exception',
     456                    'outcome'   => 'failed',
     457                    'method'    => __METHOD__,
     458                    'line'      => __LINE__,
     459                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $error_message, 'mode' => $mode ),
     460                )
     461            );
    353462            if ( function_exists( 'wc_add_notice' ) ) {
    354463                wc_add_notice( __( 'Payment error: ', 'peachpay-for-woocommerce' ) . $error_message, 'error' );
     
    362471        } catch ( \Exception $e ) {
    363472            $error_message = $e->getMessage();
    364             peachpay_log( 'error', 'Stripe.payment_intent.create.exception | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $error_message, 'mode' => $mode ) ) );
     473            peachpay_log(
     474                'error',
     475                'Stripe Payment intent create exception - failed.',
     476                array(
     477                    'event'     => 'stripe.payment_intent.create.exception',
     478                    'component' => 'payments',
     479                    'feature'   => 'payment_intent',
     480                    'operation' => 'create',
     481                    'outcome'   => 'exception',
     482                    'method'    => __METHOD__,
     483                    'line'      => __LINE__,
     484                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $error_message, 'mode' => $mode ),
     485                )
     486            );
    365487            if ( function_exists( 'wc_add_notice' ) ) {
    366488                wc_add_notice( __( 'Payment error: ', 'peachpay-for-woocommerce' ) . $error_message, 'error' );
     
    381503     */
    382504    public static function capture_payment( $order, $capture_amount ) {
    383         peachpay_log( 'debug', 'Stripe.payment_intent.capture.request | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'capture_amount' => $capture_amount ) ) );
     505        peachpay_log(
     506            'debug',
     507            'Stripe Payment intent capture request - debug.',
     508            array(
     509                'event'     => 'stripe.payment_intent.capture.request',
     510                'component' => 'payments',
     511                'feature'   => 'payment_intent',
     512                'operation' => 'capture.request',
     513                'outcome'   => 'debug',
     514                'method'    => __METHOD__,
     515                'line'      => __LINE__,
     516                'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'capture_amount' => $capture_amount ),
     517            )
     518        );
    384519
    385520        try {
     
    388523
    389524            if ( ! $stripe ) {
    390                 peachpay_log( 'error', 'Stripe.payment_intent.capture.not_configured | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'mode' => $mode ) ) );
     525                peachpay_log(
     526                    'error',
     527                    'Stripe Payment intent capture not configured - failed.',
     528                    array(
     529                        'event'     => 'stripe.payment_intent.capture.not_configured',
     530                        'component' => 'payments',
     531                        'feature'   => 'payment_intent',
     532                        'operation' => 'capture.not_configured',
     533                        'outcome'   => 'failed',
     534                        'method'    => __METHOD__,
     535                        'line'      => __LINE__,
     536                        'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'mode' => $mode ),
     537                    )
     538                );
    391539                return array(
    392540                    'success' => false,
     
    429577            self::calculate_payment_state( $order, $payment_details );
    430578
    431             peachpay_log( 'info', 'Stripe.payment_intent.capture.success | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'payment_intent_id' => $payment_intent_id, 'mode' => $mode ) ) );
     579            peachpay_log(
     580                'info',
     581                'Stripe Payment intent capture - success.',
     582                array(
     583                    'event'     => 'stripe.payment_intent.capture.success',
     584                    'component' => 'payments',
     585                    'feature'   => 'payment_intent',
     586                    'operation' => 'capture',
     587                    'outcome'   => 'success',
     588                    'method'    => __METHOD__,
     589                    'line'      => __LINE__,
     590                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'payment_intent_id' => $payment_intent_id, 'mode' => $mode ),
     591                )
     592            );
    432593            return array(
    433594                'success' => true,
     
    436597
    437598        } catch ( \Stripe\Exception\ApiErrorException $e ) {
    438             peachpay_log( 'error', 'Stripe.payment_intent.capture.api_exception | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ) ) );
     599            peachpay_log(
     600                'error',
     601                'Stripe Payment intent capture API exception - failed.',
     602                array(
     603                    'event'     => 'stripe.payment_intent.capture.api_exception',
     604                    'component' => 'payments',
     605                    'feature'   => 'payment_intent',
     606                    'operation' => 'capture.api_exception',
     607                    'outcome'   => 'failed',
     608                    'method'    => __METHOD__,
     609                    'line'      => __LINE__,
     610                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ),
     611                )
     612            );
    439613            return array(
    440614                'success' => false,
     
    442616            );
    443617        } catch ( \Exception $e ) {
    444             peachpay_log( 'error', 'Stripe.payment_intent.capture.exception | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ) ) );
     618            peachpay_log(
     619                'error',
     620                'Stripe Payment intent capture exception - failed.',
     621                array(
     622                    'event'     => 'stripe.payment_intent.capture.exception',
     623                    'component' => 'payments',
     624                    'feature'   => 'payment_intent',
     625                    'operation' => 'capture',
     626                    'outcome'   => 'exception',
     627                    'method'    => __METHOD__,
     628                    'line'      => __LINE__,
     629                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ),
     630                )
     631            );
    445632            return array(
    446633                'success' => false,
     
    457644     */
    458645    public static function void_payment( $order, $cancellation_reason = null ) {
    459         peachpay_log( 'debug', 'Stripe.payment_intent.void.request | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'cancellation_reason' => $cancellation_reason ) ) );
     646        peachpay_log(
     647            'debug',
     648            'Stripe Payment intent void request - debug.',
     649            array(
     650                'event'     => 'stripe.payment_intent.void.request',
     651                'component' => 'payments',
     652                'feature'   => 'payment_intent',
     653                'operation' => 'void.request',
     654                'outcome'   => 'debug',
     655                'method'    => __METHOD__,
     656                'line'      => __LINE__,
     657                'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'cancellation_reason' => $cancellation_reason ),
     658            )
     659        );
    460660
    461661        try {
     
    464664
    465665            if ( ! $stripe ) {
    466                 peachpay_log( 'error', 'Stripe.payment_intent.void.not_configured | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'mode' => $mode ) ) );
     666                peachpay_log(
     667                    'error',
     668                    'Stripe Payment intent void not configured - failed.',
     669                    array(
     670                        'event'     => 'stripe.payment_intent.void.not_configured',
     671                        'component' => 'payments',
     672                        'feature'   => 'payment_intent',
     673                        'operation' => 'void.not_configured',
     674                        'outcome'   => 'failed',
     675                        'method'    => __METHOD__,
     676                        'line'      => __LINE__,
     677                        'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'mode' => $mode ),
     678                    )
     679                );
    467680                return array(
    468681                    'success' => false,
     
    491704            self::calculate_payment_state( $order, $payment_details );
    492705
    493             peachpay_log( 'info', 'Stripe.payment_intent.void.success | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'payment_intent_id' => $payment_intent_id, 'mode' => $mode ) ) );
     706            peachpay_log(
     707                'info',
     708                'Stripe Payment intent void - success.',
     709                array(
     710                    'event'     => 'stripe.payment_intent.void.success',
     711                    'component' => 'payments',
     712                    'feature'   => 'payment_intent',
     713                    'operation' => 'void',
     714                    'outcome'   => 'success',
     715                    'method'    => __METHOD__,
     716                    'line'      => __LINE__,
     717                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'payment_intent_id' => $payment_intent_id, 'mode' => $mode ),
     718                )
     719            );
    494720            return array(
    495721                'success' => true,
     
    498724
    499725        } catch ( \Stripe\Exception\ApiErrorException $e ) {
    500             peachpay_log( 'error', 'Stripe.payment_intent.void.api_exception | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ) ) );
     726            peachpay_log(
     727                'error',
     728                'Stripe Payment intent void API exception - failed.',
     729                array(
     730                    'event'     => 'stripe.payment_intent.void.api_exception',
     731                    'component' => 'payments',
     732                    'feature'   => 'payment_intent',
     733                    'operation' => 'void.api_exception',
     734                    'outcome'   => 'failed',
     735                    'method'    => __METHOD__,
     736                    'line'      => __LINE__,
     737                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ),
     738                )
     739            );
    501740            return array(
    502741                'success' => false,
     
    504743            );
    505744        } catch ( \Exception $e ) {
    506             peachpay_log( 'error', 'Stripe.payment_intent.void.exception | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ) ) );
     745            peachpay_log(
     746                'error',
     747                'Stripe Payment intent void exception - failed.',
     748                array(
     749                    'event'     => 'stripe.payment_intent.void.exception',
     750                    'component' => 'payments',
     751                    'feature'   => 'payment_intent',
     752                    'operation' => 'void',
     753                    'outcome'   => 'exception',
     754                    'method'    => __METHOD__,
     755                    'line'      => __LINE__,
     756                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ),
     757                )
     758            );
    507759            return array(
    508760                'success' => false,
     
    520772     */
    521773    public static function refund_payment( $order, $amount = null, $reason = null ) {
    522         peachpay_log( 'debug', 'Stripe.payment_intent.refund.request | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'amount' => $amount, 'reason' => $reason ) ) );
     774        peachpay_log(
     775            'debug',
     776            'Stripe Payment intent refund request - debug.',
     777            array(
     778                'event'     => 'stripe.payment_intent.refund.request',
     779                'component' => 'payments',
     780                'feature'   => 'payment_intent',
     781                'operation' => 'refund.request',
     782                'outcome'   => 'debug',
     783                'method'    => __METHOD__,
     784                'line'      => __LINE__,
     785                'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'amount' => $amount, 'reason' => $reason ),
     786            )
     787        );
    523788
    524789        try {
     
    527792
    528793            if ( ! $stripe ) {
    529                 peachpay_log( 'error', 'Stripe.payment_intent.refund.not_configured | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'mode' => $mode ) ) );
     794                peachpay_log(
     795                    'error',
     796                    'Stripe Payment intent refund not configured - failed.',
     797                    array(
     798                        'event'     => 'stripe.payment_intent.refund.not_configured',
     799                        'component' => 'payments',
     800                        'feature'   => 'payment_intent',
     801                        'operation' => 'refund.not_configured',
     802                        'outcome'   => 'failed',
     803                        'method'    => __METHOD__,
     804                        'line'      => __LINE__,
     805                        'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'mode' => $mode ),
     806                    )
     807                );
    530808                return array(
    531809                    'success' => false,
     
    589867            $order->add_order_note( sprintf( __( 'Stripe %1$s payment refunded %2$s (Refund Id: %3$s)', 'peachpay-for-woocommerce' ), $order->get_payment_method_title(), $refund_amount_display, $refund->id ) );
    590868
    591             peachpay_log( 'info', 'Stripe.payment_intent.refund.success | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'payment_intent_id' => $payment_intent_id, 'refund_id' => $refund->id, 'refund_amount' => $refund->amount, 'refund_currency' => $refund->currency, 'mode' => $mode ) ) );
     869            peachpay_log(
     870                'info',
     871                'Stripe Payment intent refund - success.',
     872                array(
     873                    'event'     => 'stripe.payment_intent.refund.success',
     874                    'component' => 'payments',
     875                    'feature'   => 'payment_intent',
     876                    'operation' => 'refund',
     877                    'outcome'   => 'success',
     878                    'method'    => __METHOD__,
     879                    'line'      => __LINE__,
     880                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'payment_intent_id' => $payment_intent_id, 'refund_id' => $refund->id, 'refund_amount' => $refund->amount, 'refund_currency' => $refund->currency, 'mode' => $mode ),
     881                )
     882            );
    592883            return array(
    593884                'success' => true,
    594885                'message' => 'Success.',
     886                'refund_id' => $refund->id,
    595887            );
    596888
    597889        } catch ( \Stripe\Exception\ApiErrorException $e ) {
    598             peachpay_log( 'error', 'Stripe.payment_intent.refund.api_exception | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ) ) );
     890            peachpay_log(
     891                'error',
     892                'Stripe Payment intent refund API exception - failed.',
     893                array(
     894                    'event'     => 'stripe.payment_intent.refund.api_exception',
     895                    'component' => 'payments',
     896                    'feature'   => 'payment_intent',
     897                    'operation' => 'refund.api_exception',
     898                    'outcome'   => 'failed',
     899                    'method'    => __METHOD__,
     900                    'line'      => __LINE__,
     901                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ),
     902                )
     903            );
    599904            return array(
    600905                'success' => false,
     
    602907            );
    603908        } catch ( \Exception $e ) {
    604             peachpay_log( 'error', 'Stripe.payment_intent.refund.exception | ' . json_encode( array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ) ) );
     909            peachpay_log(
     910                'error',
     911                'Stripe Payment intent refund exception - failed.',
     912                array(
     913                    'event'     => 'stripe.payment_intent.refund.exception',
     914                    'component' => 'payments',
     915                    'feature'   => 'payment_intent',
     916                    'operation' => 'refund',
     917                    'outcome'   => 'exception',
     918                    'method'    => __METHOD__,
     919                    'line'      => __LINE__,
     920                    'data'      => array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'error_message' => $e->getMessage() ),
     921                )
     922            );
    605923            return array(
    606924                'success' => false,
     
    7551073     */
    7561074    public static function setup_payment( $session_id, $setup_intent_params ) {
    757         peachpay_log( 'debug', 'Stripe.setup_intent.create.request | ' . json_encode( array( 'session_id' => $session_id ) ) );
     1075        peachpay_log(
     1076            'debug',
     1077            'Stripe Setup intent create request - debug.',
     1078            array(
     1079                'event'     => 'stripe.setup_intent.create.request',
     1080                'component' => 'payments',
     1081                'feature'   => 'setup_intent',
     1082                'operation' => 'create.request',
     1083                'outcome'   => 'debug',
     1084                'method'    => __METHOD__,
     1085                'line'      => __LINE__,
     1086                'data'      => array( 'session_id' => $session_id ),
     1087            )
     1088        );
    7581089
    7591090        try {
     
    7621093
    7631094            if ( ! $stripe ) {
    764                 peachpay_log( 'error', 'Stripe.setup_intent.create.not_configured | ' . json_encode( array( 'session_id' => $session_id, 'mode' => $mode ) ) );
     1095                peachpay_log(
     1096                    'error',
     1097                    'Stripe Setup intent create not configured - failed.',
     1098                    array(
     1099                        'event'     => 'stripe.setup_intent.create.not_configured',
     1100                        'component' => 'payments',
     1101                        'feature'   => 'setup_intent',
     1102                        'operation' => 'create.not_configured',
     1103                        'outcome'   => 'failed',
     1104                        'method'    => __METHOD__,
     1105                        'line'      => __LINE__,
     1106                        'data'      => array( 'session_id' => $session_id, 'mode' => $mode ),
     1107                    )
     1108                );
    7651109                return array(
    7661110                    'success' => false,
     
    8281172            }
    8291173
    830             peachpay_log( 'info', 'Stripe.setup_intent.create.success | ' . json_encode( array( 'session_id' => $session_id, 'setup_intent_id' => $setup_intent->id, 'customer_id' => $setup_intent->customer, 'status' => $setup_intent->status, 'mode' => $mode ) ) );
     1174            peachpay_log(
     1175                'info',
     1176                'Stripe Setup intent create - success.',
     1177                array(
     1178                    'event'     => 'stripe.setup_intent.create.success',
     1179                    'component' => 'payments',
     1180                    'feature'   => 'setup_intent',
     1181                    'operation' => 'create',
     1182                    'outcome'   => 'success',
     1183                    'method'    => __METHOD__,
     1184                    'line'      => __LINE__,
     1185                    'data'      => array( 'session_id' => $session_id, 'setup_intent_id' => $setup_intent->id, 'customer_id' => $setup_intent->customer, 'status' => $setup_intent->status, 'mode' => $mode ),
     1186                )
     1187            );
    8311188            return array(
    8321189                'success' => true,
     
    8351192
    8361193        } catch ( \Stripe\Exception\ApiErrorException $e ) {
    837             peachpay_log( 'error', 'Stripe.setup_intent.create.api_exception | ' . json_encode( array( 'session_id' => $session_id, 'error_message' => $e->getMessage() ) ) );
     1194            peachpay_log(
     1195                'error',
     1196                'Stripe Setup intent create API exception - failed.',
     1197                array(
     1198                    'event'     => 'stripe.setup_intent.create.api_exception',
     1199                    'component' => 'payments',
     1200                    'feature'   => 'setup_intent',
     1201                    'operation' => 'create.api_exception',
     1202                    'outcome'   => 'failed',
     1203                    'method'    => __METHOD__,
     1204                    'line'      => __LINE__,
     1205                    'data'      => array( 'session_id' => $session_id, 'error_message' => $e->getMessage() ),
     1206                )
     1207            );
    8381208            return array(
    8391209                'success' => false,
     
    8411211            );
    8421212        } catch ( \Exception $e ) {
    843             peachpay_log( 'error', 'Stripe.setup_intent.create.exception | ' . json_encode( array( 'session_id' => $session_id, 'error_message' => $e->getMessage() ) ) );
     1213            peachpay_log(
     1214                'error',
     1215                'Stripe Setup intent create exception - failed.',
     1216                array(
     1217                    'event'     => 'stripe.setup_intent.create.exception',
     1218                    'component' => 'payments',
     1219                    'feature'   => 'setup_intent',
     1220                    'operation' => 'create',
     1221                    'outcome'   => 'exception',
     1222                    'method'    => __METHOD__,
     1223                    'line'      => __LINE__,
     1224                    'data'      => array( 'session_id' => $session_id, 'error_message' => $e->getMessage() ),
     1225                )
     1226            );
    8441227            return array(
    8451228                'success' => false,
  • peachpay-for-woocommerce/trunk/peachpay.php

    r3486614 r3490786  
    44 * Plugin URI: https://woocommerce.com/products/peachpay
    55 * Description: Connect and manage all your payment methods, offer shoppers a beautiful Express Checkout, and reduce cart abandonment.
    6  * Version: 1.120.22
     6 * Version: 1.120.23
    77 * Text Domain: peachpay-for-woocommerce
    88 * Domain Path: /languages
  • peachpay-for-woocommerce/trunk/readme.txt

    r3486614 r3490786  
    44Requires at least: 5.8
    55Tested up to: 6.9.1
    6 Stable tag: 1.120.22
     6Stable tag: 1.120.23
    77Requires PHP: 7.0
    88License: GPLv2 or later
     
    262262
    263263== Changelog ==
     264
     265= 1.120.23 =
     266* **Fixed**:
     267  * **Subscriptions**: Prevented duplicate subscription renewal charges across ConvesioPay and Stripe.
     268  * **Stripe**: Fixed duplicate WooCommerce refunds triggered by Stripe charge.refunded webhook.
     269* **Improved**:
     270  * **Logging**: Standardized payment logging between ConvesioPay and Stripe for better consistency and debugging.
     271  * **NMI**: Improved homepage payment box with UI reorganization and enhanced validation.
     272* **Build**:
     273  * Suppressed known CSS browser-support stylelint warnings to reduce noise in builds.
    264274
    265275= 1.120.22 =
Note: See TracChangeset for help on using the changeset viewer.