get_error_code() ? null : $lookup; } if ( empty( $lookup['merchantId'] ) ) { return new WP_Error( 'egift_bad_response', 'Unreadable eGift response.' ); } return $lookup; } /** * Sends the plugin's status report. eGift answers the same whether or not it knows the merchant. * The Webshopsleutel goes along when one is saved: eGift only counts webshop Inwisseling as on * when a valid key of that merchant came with the report. * * @param string $merchant_id The connected merchant id. * @param array $report The site URL, the versions and whether webshop Inwisseling is on. * @param string $webshopsleutel The saved key, or '' when there is none. * @return true|WP_Error True once eGift took the report, a WP_Error otherwise. */ public static function report_status( $merchant_id, array $report, $webshopsleutel ) { // A short timeout: a settings save waits for this call. $result = self::request( 'POST', '/api/wordpress/v1/merchants/' . rawurlencode( $merchant_id ) . '/status', $report, $webshopsleutel, 5 ); return is_wp_error( $result ) ? $result : true; } /** * Checks a Webshopsleutel: whose key it is and under which name the Merchant created it. * * @param string $webshopsleutel The secret the Merchant pasted. * @return array|WP_Error The check (merchantId, companyName, name, prefix), or a WP_Error. A * refused key gives code 'egift_refused' with the reason in its data. */ public static function check_webshopsleutel( $webshopsleutel ) { return self::request( 'GET', '/api/wordpress/v1/webshopsleutel', null, $webshopsleutel ); } /** * Looks up a Cadeaubon a buyer entered. Only bons of the shop's own Merchant are found; eGift * answers another merchant's bon exactly like an unknown code. * * @param string $webshopsleutel The shop's key. * @param string $code The code as the buyer typed it; eGift normalises it. * @return array|WP_Error The bon (code, remainingCredit, expirationDate), or a WP_Error. A * refused bon gives 'egift_refused' with reason unknown, not_active, * expired, no_credit or experience; too many lookups give 'egift_http_429'. */ public static function lookup_bon( $webshopsleutel, $code ) { return self::request( 'POST', '/api/wordpress/v1/giftvouchers/lookup', array( 'code' => $code ), $webshopsleutel ); } /** * Asks eGift for the Inwisseling of a bon on a paid order. Safe to repeat: eGift makes it at * most once per key, order reference and bon, and a repeat returns the original result. * * @param string $webshopsleutel The shop's key. * @param string $code The normalised code. * @param string $amount What the bon pays of the order, as a decimal string. * @param string $order_reference The order number. * @return array|WP_Error The Inwisseling (code, redeemedAmount, remainingCredit, transactionId): * redeemedAmount is less than asked when the credit ran out. A refused * bon gives 'egift_refused' with the same reasons as lookup_bon(). */ public static function redeem_bon( $webshopsleutel, $code, $amount, $order_reference ) { return self::request( 'POST', '/api/wordpress/v1/inwisselingen', array( 'code' => $code, 'amount' => (float) $amount, 'orderReference' => (string) $order_reference, ), $webshopsleutel ); } /** * Asks eGift for a Terugboeking: (part of) a bon's Inwisseling goes back on the bon because the * Merchant refunded the order. Safe to repeat with the same key: eGift makes it at most once per * key and Inwisseling, and a repeat returns the original result. * * @param string $webshopsleutel The shop's key. * @param string $code The normalised code. * @param int $inwisseling_id The transactionId the Inwisseling returned. * @param string $amount What goes back on the bon, as a decimal string. * @param string $idempotency_key The plugin's key for this Terugboeking, the same on every retry. * @return array|WP_Error The Terugboeking (code, returnedAmount, remainingCredit, expirationDate, * expired), or a WP_Error. A refusal gives 'egift_refused' with reason * unknown, no_inwisseling or exceeds_inwisseling. */ public static function return_to_bon( $webshopsleutel, $code, $inwisseling_id, $amount, $idempotency_key ) { return self::request( 'POST', '/api/wordpress/v1/terugboekingen', array( 'code' => $code, 'inwisselingId' => (int) $inwisseling_id, 'amount' => (float) $amount, 'idempotencyKey' => (string) $idempotency_key, ), $webshopsleutel ); } /** * A call to eGift, with the Webshopsleutel as a bearer token when one is given. eGift refuses an * unknown or revoked key and a blocked account with 401, and a bon the shop may not accept with * 422, each with a stable reason; that comes back as WP_Error 'egift_refused' with eGift's Dutch * message and data array( 'reason' => ..., 'status' => 401 or 422 ). Any other status outside * 2xx comes back as 'egift_http_'. * * @param string $method HTTP method. * @param string $path Path below the API base URL. * @param array|null $body JSON body, if any. * @param string $webshopsleutel The secret, or '' for a call without a key. * @param int $timeout Seconds to wait for eGift. * @return array|WP_Error The decoded JSON answer (empty for 204 No Content), or a WP_Error. */ private static function request( $method, $path, $body = null, $webshopsleutel = '', $timeout = 10 ) { $args = array( 'method' => $method, 'timeout' => $timeout, 'headers' => self::headers(), ); if ( '' !== $webshopsleutel ) { $args['headers']['Authorization'] = 'Bearer ' . $webshopsleutel; } if ( null !== $body ) { $args['headers']['Content-Type'] = 'application/json'; $args['body'] = wp_json_encode( $body ); } $response = wp_remote_request( self::api_url() . $path, $args ); if ( is_wp_error( $response ) ) { return $response; } $status = (int) wp_remote_retrieve_response_code( $response ); $decoded = json_decode( wp_remote_retrieve_body( $response ), true ); if ( 401 === $status || 422 === $status ) { return new WP_Error( 'egift_refused', is_array( $decoded ) && isset( $decoded['message'] ) ? (string) $decoded['message'] : '', array( 'reason' => is_array( $decoded ) && isset( $decoded['reason'] ) ? (string) $decoded['reason'] : 'key_unknown', 'status' => $status, ) ); } if ( $status < 200 || $status >= 300 ) { return new WP_Error( 'egift_http_' . $status, 'Unexpected eGift response status ' . $status . '.' ); } if ( 204 === $status ) { return array(); } if ( ! is_array( $decoded ) ) { return new WP_Error( 'egift_bad_response', 'Unreadable eGift response.' ); } return $decoded; } /** * Headers sent with every call. The version tells eGift which plugin release is calling. * * @return array */ private static function headers() { return array( 'Accept' => 'application/json', 'X-Egift-Plugin-Version' => EGIFT_VERSION, ); } }