diff --git a/public_html/wp-content/plugins/camptix/addons/payment-paypal.php b/public_html/wp-content/plugins/camptix/addons/payment-paypal.php index 5b40e9f40..ebbba8a1e 100644 --- a/public_html/wp-content/plugins/camptix/addons/payment-paypal.php +++ b/public_html/wp-content/plugins/camptix/addons/payment-paypal.php @@ -16,6 +16,7 @@ class CampTix_Payment_Method_PayPal extends CampTix_Payment_Method { public $id = 'paypal'; public $name = 'PayPal'; public $description = 'PayPal Express Checkout'; + protected $refund_expiry = 90; // days. public $supported_currencies = array( 'AUD', 'CAD', 'EUR', 'GBP', 'JPY', 'USD', 'NZD', 'CHF', 'HKD', 'SGD', 'SEK', 'DKK', 'PLN', 'NOK', 'HUF', 'CZK', 'ILS', 'MXN', 'BRL', 'MYR', 'PHP', 'TWD', 'THB', 'TRY', @@ -738,6 +739,30 @@ function fill_payload_with_order( &$payload, $order ) { return $payload; } + /** + * Check if the transaction is refundable. + * + * @param string $payment_token + * + * @return bool|obj WP_Error or boolean false if not refundable + */ + public function transaction_is_refundable( $payment_token ) { + /** @var CampTix_Plugin $camptix */ + global $camptix; + + if ( empty( $this->refund_expiry ) ) { + return false; + } + + $txn_details = $camptix->get_post_meta_from_payment_token( $payment_token, 'tix_transaction_details' ); + + if ( $txn_details['raw']['raw']['TIMESTAMP'] + ( $this->refund_expiry * DAY_IN_SECONDS ) < time() ) { + return new WP_Error('refund-expired', sprintf( __( 'PayPal only allows refund within %d days of payment.', 'camptix' ), $this->refund_expiry ) ); + } + + return true; + } + /** * Submits a single, user-initiated refund request to PayPal and returns the result * diff --git a/public_html/wp-content/plugins/camptix/addons/payment-stripe.php b/public_html/wp-content/plugins/camptix/addons/payment-stripe.php index 9cdcd5523..377bd177d 100644 --- a/public_html/wp-content/plugins/camptix/addons/payment-stripe.php +++ b/public_html/wp-content/plugins/camptix/addons/payment-stripe.php @@ -1,9 +1,10 @@ refund_expiry ) ) { + return false; + } + + $txn_details = $camptix->get_post_meta_from_payment_token( $payment_token, 'tix_transaction_details' ); + + if ( $txn_details['raw']['charge']['created'] + ( $this->refund_expiry * DAY_IN_SECONDS ) < time() ) { + return new WP_Error('refund-expired', sprintf( __( 'Stripe only allows refund within %d days of payment.', 'camptix' ), $this->refund_expiry ) ); + } + + return true; + } + /** * Submits a single, user-initiated refund request to Stripe and returns the result. * diff --git a/public_html/wp-content/plugins/camptix/camptix.php b/public_html/wp-content/plugins/camptix/camptix.php index 800960f00..da599211e 100644 --- a/public_html/wp-content/plugins/camptix/camptix.php +++ b/public_html/wp-content/plugins/camptix/camptix.php @@ -6076,9 +6076,7 @@ function form_access_tickets() { $edit_link = $this->get_edit_attendee_link( $attendee->ID, $edit_token ); $first_name = get_post_meta( $attendee->ID, 'tix_first_name', true ); $last_name = get_post_meta( $attendee->ID, 'tix_last_name', true ); - - if ( $this->is_refundable( $attendee->ID ) ) - $is_refundable = true; + $is_refundable = $this->is_refundable( $attendee->ID ) ?>
get_refund_tickets_link( $access_token ) ) . '">' . __( 'request a refund', 'wordcamporg' ) . '' ); ?>
+ +get_error_message() ) ) ?>
+ +get_refund_tickets_link( $access_token ) ) . '">' . __( 'request a refund', 'wordcamporg' ) . '' ); ?>
+ post_content = apply_filters( 'camptix_post_content_override', $this->shortcode_str, $post->post_content, $_GET['tix_action'] ); - if ( ! $this->options['refunds_enabled'] || ! isset( $_REQUEST['tix_access_token'] ) || ! ctype_alnum( $_REQUEST['tix_access_token'] ) ) { - $this->error_flags['invalid_access_token'] = true; - $this->redirect_with_error_flags(); - die(); - } - - $today = date( 'Y-m-d' ); - $refunds_until = $this->options['refunds_date_end']; - if ( ! strtotime( $refunds_until ) || strtotime( $refunds_until ) < strtotime( $today ) ) { - $this->error_flags['cannot_refund'] = true; - $this->redirect_with_error_flags(); - die(); - } - $access_token = $_REQUEST['tix_access_token']; // Let's get one attendee @@ -6401,6 +6389,14 @@ function form_refund_request() { $tickets = array(); foreach ( $attendees as $attendee ) { + $is_refundable = $this->is_refundable( $attendee->ID ); + if ( is_wp_error( $is_refundable ) || ! $is_refundable ) { + $this->log( 'Tried refund, but transaction is not refundable', $attendee->ID ); + $this->error_flags['cannot_refund'] = true; + $this->redirect_with_error_flags(); + die(); + } + $txn_id = get_post_meta( $attendee->ID, 'tix_transaction_id', true ); if ( $txn_id ) { $transactions[ $txn_id ] = get_post_meta( $attendee->ID, 'tix_transaction_details', true ); @@ -6419,6 +6415,7 @@ function form_refund_request() { } if ( count( $transactions ) != 1 || $transactions[ $txn_id ]['payment_amount'] <= 0 ) { + $this->log( 'Tried refund, but tno ransaction or payment amount 0', $attendee->ID ); $this->error_flags['cannot_refund'] = true; $this->redirect_with_error_flags(); die(); @@ -6426,6 +6423,7 @@ function form_refund_request() { $transaction = array_shift( $transactions ); if ( ! $transaction['receipt_email'] || ! $transaction['transaction_id'] || ! $transaction['payment_amount'] ) { + $this->log( 'Tried refund, but problems with original transaction', $attendee->ID ); $this->error_flags['cannot_refund'] = true; $this->redirect_with_error_flags(); die(); @@ -6445,6 +6443,7 @@ function form_refund_request() { // Bail if a payment method does not exist. if ( ! $payment_method_obj ) { + $this->log( 'Tried refund, but payment method does not exist', $attendee->ID ); $this->error_flags['cannot_refund'] = true; $this->redirect_with_error_flags(); die(); @@ -6548,26 +6547,39 @@ function form_refund_success() { * Return true if an attendee_id is refundable. */ function is_refundable( $attendee_id ) { - if ( ! $this->options['refunds_enabled'] ) - return false; - - $payment_method = get_post_meta( $attendee_id, 'tix_payment_method', true ); - $payment_method_obj = $this->get_payment_method_by_id( $payment_method ); - if ( ! $payment_method_obj || ! $payment_method_obj->supports_feature( 'refund-single' ) ) + if ( ! $this->options['refunds_enabled'] ) { return false; + } - $today = date( 'Y-m-d' ); + $today = date( 'Y-m-d' ); $refunds_until = $this->options['refunds_date_end']; - if ( ! strtotime( $refunds_until ) ) + if ( ! strtotime( $refunds_until ) ) { return false; + } - if ( strtotime( $refunds_until ) < strtotime( $today ) ) + if ( strtotime( $refunds_until ) < strtotime( $today ) ) { return false; + } - $attendee = get_post( $attendee_id ); - if ( $attendee->post_status == 'publish' && (float) get_post_meta( $attendee->ID, 'tix_order_total', true ) > 0 && get_post_meta( $attendee->ID, 'tix_transaction_id', true ) ) + $payment_method = get_post_meta( $attendee_id, 'tix_payment_method', true ); + $payment_method_obj = $this->get_payment_method_by_id( $payment_method ); + + if ( ! $payment_method_obj || ! $payment_method_obj->supports_feature( 'refund-single' ) ) { + return false; + } + + $attendee = get_post( $attendee_id ); + $payment_token = get_post_meta( $attendee->ID, 'tix_payment_token', true ); + $is_refundable = $payment_method_obj->transaction_is_refundable( $payment_token ); + + if ( is_wp_error( $is_refundable ) ) { + return $is_refundable; + } + + if ( $attendee->post_status == 'publish' && (float) get_post_meta( $attendee->ID, 'tix_order_total', true ) > 0 && get_post_meta( $attendee->ID, 'tix_transaction_id', true ) ) { return true; + } return false; } diff --git a/public_html/wp-content/plugins/camptix/inc/class-camptix-payment-method.php b/public_html/wp-content/plugins/camptix/inc/class-camptix-payment-method.php index 4fca40265..7f43f35da 100644 --- a/public_html/wp-content/plugins/camptix/inc/class-camptix-payment-method.php +++ b/public_html/wp-content/plugins/camptix/inc/class-camptix-payment-method.php @@ -216,6 +216,17 @@ function validate_options( $input ) { */ abstract function payment_checkout( $payment_token ); + /** + * Check if the transaction is refundable. + * + * @param string $payment_token + * + * @return bool|obj WP_Error or boolean false if not refundable + */ + public function transaction_is_refundable( $payment_token ) { + return true; // To maintain backwards compatibility, default to refundable. + } + /** * Handle the refund process *