request = $request; // `get_params()` returns an array, but we want an object. $this->event = json_decode( json_encode( $this->request->get_params() ) ); } /** * Handles the webhook event. * * @throws \Exception */ public function handle() { $this->process_event(); } /** * Processes the event. * * @since 2.11 * @return void */ abstract protected function process_event(); /** * Retrieves an Order record from a capture event. * * @since 3.0 * * @return Order * @throws \Exception */ protected function get_order_from_capture() { if ( 'capture' !== $this->request->get_param( 'resource_type' ) ) { throw new \Exception( sprintf( 'get_payment_from_capture() - Invalid resource type: %s', $this->request->get_param( 'resource_type' ) ) ); } if ( empty( $this->event->resource ) ) { throw new \Exception( sprintf( 'get_payment_from_capture() - Missing event resource.' ) ); } return $this->get_order_from_capture_object( $this->event->resource ); } /** * Retrieves an Order record from a capture object. * * @param object $resource * * @since 3.0 * * @return Order * @throws \Exception */ protected function get_order_from_capture_object( $resource ) { $order = false; if ( ! empty( $resource->custom_id ) && is_numeric( $resource->custom_id ) ) { $order = edd_get_order( $resource->custom_id ); } if ( empty( $order ) && ! empty( $resource->id ) ) { $order_id = edd_get_order_id_from_transaction_id( $resource->id ); $order = $order_id ? edd_get_order( $order_id ) : false; } if ( ! $order instanceof Order ) { throw new \Exception( 'get_order_from_capture_object() - Failed to locate order.', 200 ); } /* * Verify the transaction ID. This covers us in case we fetched the order via `custom_id`, but * it wasn't actually an EDD-initiated payment. */ $order_transaction_id = $order->get_transaction_id(); if ( $order_transaction_id !== $resource->id ) { throw new \Exception( sprintf( 'get_order_from_capture_object() - Transaction ID mismatch. Expected: %s; Actual: %s', $order_transaction_id, $resource->id ), 200 ); } return $order; } /** * Retrieves an Order record from a refund event. * * @since 3.0 * * @return Order * @throws API_Exception * @throws Authentication_Exception * @throws \Exception */ protected function get_order_from_refund() { edd_debug_log( sprintf( 'PayPal Commerce Webhook - get_payment_from_capture_object() - Resource type: %s; Resource ID: %s', $this->request->get_param( 'resource_type' ), $this->event->resource->id ) ); if ( empty( $this->event->resource->links ) || ! is_array( $this->event->resource->links ) ) { throw new \Exception( 'Missing resources.', 200 ); } $order_link = current( array_filter( $this->event->resource->links, function ( $link ) { return ! empty( $link->rel ) && 'up' === strtolower( $link->rel ); } ) ); if ( empty( $order_link->href ) ) { throw new \Exception( 'Missing order link.', 200 ); } // Based on the payment link, determine which mode we should act in. if ( false === strpos( $order_link->href, 'sandbox.paypal.com' ) ) { $mode = API::MODE_LIVE; } else { $mode = API::MODE_SANDBOX; } // Look up the full order record in PayPal. $api = new API( $mode ); $response = $api->make_request( $order_link->href, array(), array(), $order_link->method ); if ( 200 !== $api->last_response_code ) { throw new API_Exception( sprintf( 'Invalid response code when retrieving order record: %d', $api->last_response_code ) ); } if ( empty( $response->id ) ) { throw new API_Exception( 'Missing order ID from API response.' ); } return $this->get_order_from_capture_object( $response ); } /** * Retrieves an EDD_Payment record from a capture event. * * @since 2.11 * @deprecated 3.0 In favour of `get_order_from_capture()` * @see Webhook_Event::get_order_from_capture() * * @return \EDD_Payment * @throws \Exception */ protected function get_payment_from_capture() { if ( 'capture' !== $this->request->get_param( 'resource_type' ) ) { throw new \Exception( sprintf( 'get_payment_from_capture() - Invalid resource type: %s', $this->request->get_param( 'resource_type' ) ) ); } if ( empty( $this->event->resource ) ) { throw new \Exception( sprintf( 'get_payment_from_capture() - Missing event resource.' ) ); } return $this->get_payment_from_capture_object( $this->event->resource ); } /** * Retrieves an EDD_Payment record from a capture object. * * @param object $resource * * @since 2.11 * @deprecated 3.0 In favour of `get_order_from_capture_object()` * @see Webhook_Event::get_order_from_capture_object * * @return \EDD_Payment * @throws \Exception */ protected function get_payment_from_capture_object( $resource ) { $payment = false; if ( ! empty( $resource->custom_id ) && is_numeric( $resource->custom_id ) ) { $payment = edd_get_payment( $resource->custom_id ); } if ( empty( $payment ) && ! empty( $resource->id ) ) { $payment_id = edd_get_purchase_id_by_transaction_id( $resource->id ); $payment = $payment_id ? edd_get_payment( $payment_id ) : false; } if ( ! $payment instanceof \EDD_Payment ) { throw new \Exception( 'get_payment_from_capture_object() - Failed to locate payment.', 200 ); } /* * Verify the transaction ID. This covers us in case we fetched the payment via `custom_id`, but * it wasn't actually an EDD-initiated payment. */ if ( $payment->transaction_id !== $resource->id ) { throw new \Exception( sprintf( 'get_payment_from_capture_object() - Transaction ID mismatch. Expected: %s; Actual: %s', $payment->transaction_id, $resource->id ), 200 ); } return $payment; } /** * Retrieves an EDD_Payment record from a refund event. * * @since 2.11 * @deprecated 3.0 In favour of `get_order_from_refund` * @see Webhook_Event::get_order_from_refund * * @return \EDD_Payment * @throws API_Exception * @throws Authentication_Exception * @throws \Exception */ protected function get_payment_from_refund() { edd_debug_log( sprintf( 'PayPal Commerce Webhook - get_payment_from_refund() - Resource type: %s; Resource ID: %s', $this->request->get_param( 'resource_type' ), $this->event->resource->id ) ); if ( empty( $this->event->resource->links ) || ! is_array( $this->event->resource->links ) ) { throw new \Exception( 'Missing resources.', 200 ); } $order_link = current( array_filter( $this->event->resource->links, function ( $link ) { return ! empty( $link->rel ) && 'up' === strtolower( $link->rel ); } ) ); if ( empty( $order_link->href ) ) { throw new \Exception( 'Missing order link.', 200 ); } // Based on the payment link, determine which mode we should act in. if ( false === strpos( $order_link->href, 'sandbox.paypal.com' ) ) { $mode = API::MODE_LIVE; } else { $mode = API::MODE_SANDBOX; } // Look up the full order record in PayPal. $api = new API( $mode ); $response = $api->make_request( $order_link->href, array(), array(), $order_link->method ); if ( 200 !== $api->last_response_code ) { throw new API_Exception( sprintf( 'Invalid response code when retrieving order record: %d', $api->last_response_code ) ); } if ( empty( $response->id ) ) { throw new API_Exception( 'Missing order ID from API response.' ); } return $this->get_payment_from_capture_object( $response ); } }