From b00d545a10d325bce90d577d37f4a5153a091492 Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Mon, 18 Oct 2021 18:24:38 +0900 Subject: [PATCH] Amazon Gift Card on Demand Incentives stand alone class --- src/Amazon/AWS/AWS.php | 429 ++++++++++++++++++ src/Amazon/AmazonIncentives.php | 182 ++++++++ src/Amazon/Client/Client.php | 86 ++++ src/Amazon/Client/ClientInterface.php | 18 + src/Amazon/Config/Config.php | 172 +++++++ src/Amazon/Config/ConfigInterface.php | 63 +++ src/Amazon/Debug/AmazonDebug.php | 56 +++ src/Amazon/Exceptions/AmazonErrors.php | 37 ++ src/Amazon/Response/CancelResponse.php | 111 +++++ src/Amazon/Response/CreateBalanceResponse.php | 129 ++++++ src/Amazon/Response/CreateResponse.php | 201 ++++++++ test/autoloader.php | 63 +++ test/aws_gift_card_tests.php | 141 ++++++ test/read_env_file.php | 84 ++++ 14 files changed, 1772 insertions(+) create mode 100644 src/Amazon/AWS/AWS.php create mode 100644 src/Amazon/AmazonIncentives.php create mode 100644 src/Amazon/Client/Client.php create mode 100644 src/Amazon/Client/ClientInterface.php create mode 100644 src/Amazon/Config/Config.php create mode 100644 src/Amazon/Config/ConfigInterface.php create mode 100644 src/Amazon/Debug/AmazonDebug.php create mode 100644 src/Amazon/Exceptions/AmazonErrors.php create mode 100644 src/Amazon/Response/CancelResponse.php create mode 100644 src/Amazon/Response/CreateBalanceResponse.php create mode 100644 src/Amazon/Response/CreateResponse.php create mode 100644 test/autoloader.php create mode 100644 test/aws_gift_card_tests.php create mode 100644 test/read_env_file.php diff --git a/src/Amazon/AWS/AWS.php b/src/Amazon/AWS/AWS.php new file mode 100644 index 0000000..703447b --- /dev/null +++ b/src/Amazon/AWS/AWS.php @@ -0,0 +1,429 @@ +config = $config; + AmazonDebug::setFlag($config->getDebug()); + AmazonDebug::setId(); + AmazonDebug::writeLog([__METHOD__ => date('Y-m-d H:m:s.u')]); + } + + /** + * @param float $amount + * @param string|null $creation_id + * @return CreateResponse + * + * @throws AmazonErrors + */ + public function getCode(float $amount, ?string $creation_id = null): CreateResponse + { + $service_operation = self::CREATE_GIFT_CARD_SERVICE; + $payload = $this->getGiftCardPayload($amount, $creation_id); + $canonical_request = $this->getCanonicalRequest($service_operation, $payload); + $date_time_string = $this->getTimestamp(); + AmazonDebug::writeLog(['call' => __METHOD__]); + $result = json_decode($this->makeRequest( + $payload, + $canonical_request, + $service_operation, + $date_time_string + ), true); + return new CreateResponse($result); + } + + /** + * @param string $creation_request_id + * @param string $gift_card_id + * @return CancelResponse + * + * @throws AmazonErrors + */ + public function cancelCode(string $creation_request_id, string $gift_card_id): CancelResponse + { + $service_operation = self::CANCEL_GIFT_CARD_SERVICE; + $payload = $this->getCancelGiftCardPayload($creation_request_id, $gift_card_id); + $canonical_request = $this->getCanonicalRequest($service_operation, $payload); + $date_time_string = $this->getTimestamp(); + AmazonDebug::writeLog(['call' => __METHOD__]); + $result = json_decode($this->makeRequest( + $payload, + $canonical_request, + $service_operation, + $date_time_string + ), true); + return new CancelResponse($result); + } + + /** + * @return CreateBalanceResponse + * + * @throws AmazonErrors + */ + public function getBalance(): CreateBalanceResponse + { + $service_operation = self::GET_AVAILABLE_FUNDS_SERVICE; + $payload = $this->getAvailableFundsPayload(); + $canonical_request = $this->getCanonicalRequest($service_operation, $payload); + $date_time_string = $this->getTimestamp(); + AmazonDebug::writeLog(['call' => __METHOD__]); + $result = json_decode($this->makeRequest( + $payload, + $canonical_request, + $service_operation, + $date_time_string + ), true); + return new CreateBalanceResponse($result); + } + + /** + * @param string $payload + * @param string $canonical_request + * @param string $service_operation + * @param string $date_time_string + * @return string + */ + public function makeRequest( + string $payload, + string $canonical_request, + string $service_operation, + string $date_time_string + ): string { + // debug + AmazonDebug::writeLog([__METHOD__ => [ + 'Operation' => $service_operation, + 'Payload' => $payload, + 'Cannonical Request' => $canonical_request, + 'Date Time String' => $date_time_string + + ]]); + $KEY_QUALIFIER = self::KEY_QUALIFIER; + $canonical_request_hash = $this->buildHash($canonical_request); + $string_to_sign = $this->buildStringToSign($canonical_request_hash); + $authorization_value = $this->buildAuthSignature($string_to_sign); + + $secret_key = $this->config->getSecret(); + $endpoint = $this->config->getEndpoint(); + $region_name = $this->getRegion(); + + $SERVICE_NAME = 'AGCODService'; + $service_target = 'com.amazonaws.agcod.' . $SERVICE_NAME . '.' . $service_operation; + $date_string = $this->getDateString(); + + $signature_aws_key = $KEY_QUALIFIER . $secret_key; + + $k_date = $this->hmac($date_string, $signature_aws_key); + $k_date_hexis = $this->hmac($date_string, $signature_aws_key, false); + $k_region = $this->hmac($region_name, $k_date); + $k_region_hexis = $this->hmac($region_name, $k_date, false); + $k_service_hexis = $this->hmac($SERVICE_NAME, $k_region, false); + + AmazonDebug::writeLog([__METHOD__ => [ + 'Date' => $k_date_hexis, + 'Region' => $k_region_hexis, + 'Service' => $k_service_hexis, + ]]); + + $url = 'https://' . $endpoint . '/' . $service_operation; + $headers = $this->buildHeaders($payload, $authorization_value, $date_time_string, $service_target); + return (new Client())->request($url, $headers, $payload); + } + + /** + * @param string $payload + * @param string $authorization_value + * @param string $date_time_string + * @param string $service_target + * @return array + */ + public function buildHeaders( + string $payload, + string $authorization_value, + string $date_time_string, + string $service_target + ): array { + $ACCEPT_HEADER = self::ACCEPT_HEADER; + $X_AMZ_DATE_HEADER = self::X_AMZ_DATE_HEADER; + $X_AMZ_TARGET_HEADER = self::X_AMZ_TARGET_HEADER; + $AUTHORIZATION_HEADER = self::AUTHORIZATION_HEADER; + return [ + 'Content-Type:' . $this->getContentType(), + 'Content-Length: ' . strlen($payload), + $AUTHORIZATION_HEADER . ':' . $authorization_value, + $X_AMZ_DATE_HEADER . ':' . $date_time_string, + $X_AMZ_TARGET_HEADER . ':' . $service_target, + $ACCEPT_HEADER . ':' . $this->getContentType() + ]; + } + + /** + * @param string $string_to_sign + * @return string + */ + public function buildAuthSignature(string $string_to_sign): string + { + $AWS_SHA256_ALGORITHM = self::AWS_SHA256_ALGORITHM; + $SERVICE_NAME = self::SERVICE_NAME; + $TERMINATION_STRING = self::TERMINATION_STRING; + $ACCEPT_HEADER = self::ACCEPT_HEADER; + $HOST_HEADER = self::HOST_HEADER; + $X_AMZ_DATE_HEADER = self::X_AMZ_DATE_HEADER; + $X_AMZ_TARGET_HEADER = self::X_AMZ_TARGET_HEADER; + + $aws_key_id = $this->config->getAccessKey(); + $region_name = $this->getRegion(); + + $date_string = $this->getDateString(); + $derived_key = $this->buildDerivedKey(); + // Calculate signature per http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html + $final_signature = $this->hmac($string_to_sign, $derived_key, false); + + // Assemble Authorization Header with signing information + // per http://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html + $authorization_value = + $AWS_SHA256_ALGORITHM + . ' Credential=' . $aws_key_id + . '/' . $date_string . '/' . $region_name . '/' . $SERVICE_NAME . '/' . $TERMINATION_STRING . ',' + . ' SignedHeaders=' + . $ACCEPT_HEADER . ';' . $HOST_HEADER . ';' . $X_AMZ_DATE_HEADER . ';' . $X_AMZ_TARGET_HEADER . ',' + . ' Signature=' + . $final_signature; + + return $authorization_value; + } + + /** + * @param string $canonical_request_hash + * @return string + */ + public function buildStringToSign($canonical_request_hash): string + { + $AWS_SHA256_ALGORITHM = self::AWS_SHA256_ALGORITHM; + $TERMINATION_STRING = self::TERMINATION_STRING; + $SERVICE_NAME = self::SERVICE_NAME; + $region_name = $this->getRegion(); + $date_time_string = $this->getTimestamp(); + $date_string = $this->getDateString(); + $string_to_sign = "$AWS_SHA256_ALGORITHM\n" + . "$date_time_string\n" + . "$date_string/$region_name/$SERVICE_NAME/$TERMINATION_STRING\n" + . "$canonical_request_hash"; + + return $string_to_sign; + } + + /** + * @param bool $rawOutput + * @return string + */ + public function buildDerivedKey(bool $rawOutput = true): string + { + $KEY_QUALIFIER = self::KEY_QUALIFIER; + $TERMINATION_STRING = self::TERMINATION_STRING; + $SERVICE_NAME = self::SERVICE_NAME; + + $aws_secret_key = $this->config->getSecret(); + // Append Key Qualifier, "AWS4", to secret key per + // shttp://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html + $signature_aws_key = $KEY_QUALIFIER . $aws_secret_key; + $region_name = $this->getRegion(); + $date_string = $this->getDateString(); + + $k_date = $this->hmac($date_string, $signature_aws_key); + $k_region = $this->hmac($region_name, $k_date); + $k_service = $this->hmac($SERVICE_NAME, $k_region); + + // Derived the Signing key (derivedKey aka kSigning) + return $this->hmac($TERMINATION_STRING, $k_service, $rawOutput); + } + + /** + * @return string + */ + public function getRegion(): string + { + $endpoint = $this->config->getEndpoint(); + // default region + $region_name = 'us-east-1'; + + switch ($endpoint) { + case 'agcod-v2.amazon.com': + case 'agcod-v2-gamma.amazon.com': + $region_name = 'us-east-1'; + break; + case 'agcod-v2-eu.amazon.com': + case 'agcod-v2-eu-gamma.amazon.com': + $region_name = 'us-west-1'; + break; + case 'agcod-v2-fe.amazon.com': + case 'agcod-v2-fe-gamma.amazon.com': + $region_name = 'us-west-2'; + break; + } + return $region_name; + } + + + /** + * @param float $amount + * @param string $creation_id + * @return string + */ + public function getGiftCardPayload(float $amount, ?string $creation_id = null): string + { + $amount = trim($amount); + $payload = [ + 'creationRequestId' => $creation_id ?: uniqid($this->config->getPartner() . '_'), + 'partnerId' => $this->config->getPartner(), + 'value' => + [ + 'currencyCode' => $this->config->getCurrency(), + 'amount' => (float)$amount + ] + ]; + return json_encode($payload); + } + + /** + * @param string $creation_request_id + * @param string $gift_card_id + * @return string + */ + public function getCancelGiftCardPayload(string $creation_request_id, string $gift_card_id): string + { + $gift_card_response_id = trim($gift_card_id); + $payload = [ + 'creationRequestId' => $creation_request_id, + 'partnerId' => $this->config->getPartner(), + 'gcId' => $gift_card_response_id + ]; + return json_encode($payload); + } + + /** + * @return string + */ + public function getAvailableFundsPayload(): string + { + $payload = [ + 'partnerId' => $this->config->getPartner(), + ]; + return json_encode($payload); + } + + /** + * @param string $service_operation + * @param string $payload + * @return string + */ + public function getCanonicalRequest(string $service_operation, string $payload): string + { + $HOST_HEADER = self::HOST_HEADER; + $X_AMZ_DATE_HEADER = self::X_AMZ_DATE_HEADER; + $X_AMZ_TARGET_HEADER = self::X_AMZ_TARGET_HEADER; + $ACCEPT_HEADER = self::ACCEPT_HEADER; + $payload_hash = $this->buildHash($payload); + $canonical_headers = $this->buildCanonicalHeaders($service_operation); + $canonical_request = "POST\n" + . "/$service_operation\n\n" + . "$canonical_headers\n\n" + . "$ACCEPT_HEADER;$HOST_HEADER;$X_AMZ_DATE_HEADER;$X_AMZ_TARGET_HEADER\n" + . "$payload_hash"; + return $canonical_request; + } + + /** + * @param string $data + * @return string + */ + public function buildHash(string $data): string + { + return hash('sha256', $data); + } + + /** + * @return false|string + */ + public function getTimestamp() + { + return gmdate('Ymd\THis\Z'); + } + + /** + * @param string $data + * @param string $key + * @param bool $raw + * @return string + */ + public function hmac(string $data, string $key, bool $raw = true): string + { + return hash_hmac('sha256', $data, $key, $raw); + } + + /** + * @return bool|string + */ + public function getDateString() + { + return substr($this->getTimestamp(), 0, 8); + } + + /** + * @return string + */ + public function getContentType(): string + { + return 'application/json'; + } + + /** + * @param string $service_operation + * @return string + */ + public function buildCanonicalHeaders(string $service_operation): string + { + $ACCEPT_HEADER = self::ACCEPT_HEADER; + $HOST_HEADER = self::HOST_HEADER; + $X_AMZ_DATE_HEADER = self::X_AMZ_DATE_HEADER; + $X_AMZ_TARGET_HEADER = self::X_AMZ_TARGET_HEADER; + $date_time_string = $this->getTimestamp(); + $endpoint = $this->config->getEndpoint(); + $content_type = $this->getContentType(); + return "$ACCEPT_HEADER:$content_type\n" + . "$HOST_HEADER:$endpoint\n" + . "$X_AMZ_DATE_HEADER:$date_time_string\n" + . "$X_AMZ_TARGET_HEADER:com.amazonaws.agcod.AGCODService.$service_operation"; + } +} + +// __END__ diff --git a/src/Amazon/AmazonIncentives.php b/src/Amazon/AmazonIncentives.php new file mode 100644 index 0000000..0dac5ea --- /dev/null +++ b/src/Amazon/AmazonIncentives.php @@ -0,0 +1,182 @@ +config = new Config($key, $secret, $partner, $endpoint, $currency, $debug); + } + + // ********************************************************************* + // PRIVATE HELPER METHODS + // ********************************************************************* + + // ********************************************************************* + // PUBLIC DEBUG METHODS + // ********************************************************************* + + // like log collector (array) and returner + + // ********************************************************************* + // PUBLIC METHODS + // ********************************************************************* + + // public function activateGiftCard(): array + // { + // return []; + // } + + // public function deactivateGiftCard(string $card_id): array + // { + // return []; + // } + + // public function activationStatusCheck(string $card_id): array + // { + // return []; + // } + + /** + * @param float $value + * @param string $creation_request_id AWS creationRequestId + * @return Response\CreateResponse + * + * @throws AmazonErrors + */ + public function buyGiftCard(float $value, string $creation_request_id = null): Response\CreateResponse + { + return (new AWS($this->config))->getCode($value, $creation_request_id); + } + + + /** + * @param string $creation_request_id AWS creationRequestId + * @param string $gift_card_id AWS gcId + * @return Response\CancelResponse + */ + public function cancelGiftCard(string $creation_request_id, string $gift_card_id): Response\CancelResponse + { + return (new AWS($this->config))->cancelCode($creation_request_id, $gift_card_id); + } + + /** + * @return Response\CreateBalanceResponse + * + * @throws AmazonErrors + */ + public function getAvailableFunds(): Response\CreateBalanceResponse + { + return (new AWS($this->config))->getBalance(); + } + + /** + * AmazonGiftCode make own client. + * + * @param string|null $key + * @param string|null $secret + * @param string|null $partner + * @param string|null $endpoint + * @param string|null $currency + * @param bool|null $debug + * @return AmazonGiftCode + */ + public static function make( + string $key = null, + string $secret = null, + string $partner = null, + string $endpoint = null, + string $currency = null, + bool $debug = null + ): AmazonIncentives { + return new static($key, $secret, $partner, $endpoint, $currency, $debug); + } + + /** + * Decodes the Exception message body + * Returns an array with code (Amazon error codes), type (Amazon error info) + * message (Amazon returned error message string) + * + * @param string $message Exception message json string + * @return array Decoded with code, type, message fields + */ + public static function decodeExceptionMessage(string $message): array + { + return json_decode($message, true); + } + // ********************************************************************* + // PUBLIC TEST METHODS + // ********************************************************************* + + public function checkMe(): array + { + $data = []; + + $data['ENV'] = $_ENV; + $data['CONFIG'] = $this->config; + $data['KEY'] = $this->config->getAccessKey(); + + return $data; + } +} + +// __END__ diff --git a/src/Amazon/Client/Client.php b/src/Amazon/Client/Client.php new file mode 100644 index 0000000..271ce3f --- /dev/null +++ b/src/Amazon/Client/Client.php @@ -0,0 +1,86 @@ +handleCurlError($url, $err, $message); + } + + if (curl_getinfo($handle, CURLINFO_HTTP_CODE) !== self::HTTP_OK) { + $err = curl_errno($handle); + // extract all the error codes from Amazon + $error_code = json_decode($result)->errorCode; + $error_type = json_decode($result)->errorType; + $message = json_decode($result)->message; + throw AmazonErrors::getError( + $error_code, + $error_type, + $message, + $err + ); + } + return $result; + } + + /** + * Undocumented function + * + * @param string $url + * @param string $errno + * @param string $message + * @return void + */ + private function handleCurlError(string $url, int $errno, string $message): void + { + switch ($errno) { + case CURLE_COULDNT_CONNECT: + case CURLE_COULDNT_RESOLVE_HOST: + case CURLE_OPERATION_TIMEOUTED: + $msg = 'Could not connect to AWS (' . $url . '). Please check your ' + . 'internet connection and try again.'; + break; + case CURLE_SSL_CACERT: + case CURLE_SSL_PEER_CERTIFICATE: + $msg = 'Could not verify AWS SSL certificate. Please make sure ' + . 'that your network is not intercepting certificates. ' + . '(Try going to ' . $url . 'in your browser.) ' + . 'If this problem persists,'; + break; + case 0: + default: + $msg = 'Unexpected error communicating with AWS. ' . $message; + } + + throw new \RuntimeException($msg); + } +} + +// __END__ diff --git a/src/Amazon/Client/ClientInterface.php b/src/Amazon/Client/ClientInterface.php new file mode 100644 index 0000000..9cf299f --- /dev/null +++ b/src/Amazon/Client/ClientInterface.php @@ -0,0 +1,18 @@ +setAccessKey($key ?: $_ENV['AWS_GIFT_CARD_KEY'] ?? ''); + $this->setSecret($secret ?: $_ENV['AWS_GIFT_CARD_SECRET'] ?? ''); + $this->setPartner($partner ?: $_ENV['AWS_GIFT_CARD_PARTNER_ID'] ?? ''); + $this->setEndpoint($endpoint ?: $_ENV['AWS_GIFT_CARD_ENDPOINT'] ?? ''); + $this->setCurrency($currency ?: $_ENV['AWS_GIFT_CARD_CURRENCY'] ?? ''); + $this->setDebug($debug ?: (!empty($_ENV['AWS_DEBUG']) ? true : false)); + } + + /** + * @return string + */ + public function getEndpoint(): string + { + return $this->endpoint; + } + + /** + * @param string $endpoint + * @return ConfigInterface + */ + public function setEndpoint(string $endpoint): ConfigInterface + { + // TODO: check valid endpoint + set region + $this->endpoint = parse_url($endpoint, PHP_URL_HOST); + + return $this; + } + + /** + * @return string + */ + public function getAccessKey(): string + { + return $this->access_key; + } + + /** + * @param string $key + * @return ConfigInterface + */ + public function setAccessKey(string $key): ConfigInterface + { + $this->access_key = $key; + + return $this; + } + + /** + * @return string + */ + public function getSecret(): string + { + return $this->secret_key; + } + + /** + * @param string $secret + * @return ConfigInterface + */ + public function setSecret(string $secret): ConfigInterface + { + $this->secret_key = $secret; + + return $this; + } + + /** + * @return string + */ + public function getCurrency(): string + { + return $this->currency; + } + + /** + * @param string $currency + * @return ConfigInterface + */ + public function setCurrency(string $currency): ConfigInterface + { + // TODO: check currency valid + currenc valid for region + $this->currency = $currency; + + return $this; + } + + /** + * @return string + */ + public function getPartner(): string + { + return $this->partner_id; + } + + /** + * @param string $partner + * @return ConfigInterface + */ + public function setPartner(string $partner): ConfigInterface + { + $this->partner_id = $partner; + + return $this; + } + + /** + * @return bool + */ + public function getDebug(): bool + { + return $this->debug; + } + + /** + * @param bool $debug + * @return ConfigInterface + */ + public function setDebug(bool $debug): ConfigInterface + { + $this->debug = $debug; + + return $this; + } +} + +// __END__ diff --git a/src/Amazon/Config/ConfigInterface.php b/src/Amazon/Config/ConfigInterface.php new file mode 100644 index 0000000..3a2d653 --- /dev/null +++ b/src/Amazon/Config/ConfigInterface.php @@ -0,0 +1,63 @@ + $error_code, + 'type' => $error_type, + 'message' => $message, + // atach log data if exists + 'log_id' => \Amazon\Debug\AmazonDebug::getId(), + 'log' => \Amazon\Debug\AmazonDebug::getLog(), + ]), + $_error_code + ); + } +} + +// __END__ diff --git a/src/Amazon/Response/CancelResponse.php b/src/Amazon/Response/CancelResponse.php new file mode 100644 index 0000000..0d5df5a --- /dev/null +++ b/src/Amazon/Response/CancelResponse.php @@ -0,0 +1,111 @@ +raw_json = $json_response; + $this->log = \Amazon\Debug\AmazonDebug::getLog(\Amazon\Debug\AmazonDebug::getId()); + $this->parseJsonResponse($json_response); + } + + /** + * @return array + */ + public function getLog(): array + { + return $this->log; + } + + /** + * @return string + */ + public function getId(): string + { + return $this->id; + } + + /** + * @return string + */ + public function getCreationRequestId(): string + { + return $this->creation_request_id; + } + + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @return string + */ + public function getRawJson(): string + { + return json_encode($this->raw_json); + } + + /** + * @param array $json_response + * @return CancelResponse + */ + public function parseJsonResponse(array $json_response): self + { + if (!is_array($json_response)) { + throw new \RuntimeException('Response must be a scalar value'); + } + if (array_key_exists('gcId', $json_response)) { + $this->id = $json_response['gcId']; + } + if (array_key_exists('creationRequestId', $json_response)) { + $this->creation_request_id = $json_response['creationRequestId']; + } + // SUCCESS, FAILURE, RESEND + if (array_key_exists('status', $json_response)) { + $this->status = $json_response['status']; + } + + return $this; + } +} + +// __END__ diff --git a/src/Amazon/Response/CreateBalanceResponse.php b/src/Amazon/Response/CreateBalanceResponse.php new file mode 100644 index 0000000..7fdb3e9 --- /dev/null +++ b/src/Amazon/Response/CreateBalanceResponse.php @@ -0,0 +1,129 @@ +raw_json = $json_response; + $this->log = \Amazon\Debug\AmazonDebug::getLog(\Amazon\Debug\AmazonDebug::getId()); + $this->parseJsonResponse($json_response); + } + + /** + * @return array + */ + public function getLog(): array + { + return $this->log; + } + + /** + * @return string + */ + public function getAmount(): string + { + return $this->amount; + } + + /** + * @return string + */ + public function getCurrency(): string + { + return $this->currency; + } + + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @return string + */ + public function getTimestamp(): string + { + return $this->timestamp; + } + + /** + * @return string + */ + public function getRawJson(): string + { + return json_encode($this->raw_json); + } + + /** + * Undocumented function + * + * @param array $json_response + * @return CreateBalanceResponse + */ + public function parseJsonResponse(array $json_response): self + { + if (!is_array($json_response)) { + throw new \RuntimeException('Response must be a scalar value'); + } + if (array_key_exists('amount', $json_response['availableFunds'])) { + $this->amount = $json_response['availableFunds']['amount']; + } + if (array_key_exists('currencyCode', $json_response['availableFunds'])) { + $this->currency = $json_response['availableFunds']['currencyCode']; + } + // SUCCESS, FAILURE, RESEND + if (array_key_exists('status', $json_response)) { + $this->status = $json_response['status']; + } + if (array_key_exists('timestamp', $json_response)) { + $this->timestamp = $json_response['timestamp']; + } + + return $this; + } +} diff --git a/src/Amazon/Response/CreateResponse.php b/src/Amazon/Response/CreateResponse.php new file mode 100644 index 0000000..e7d2162 --- /dev/null +++ b/src/Amazon/Response/CreateResponse.php @@ -0,0 +1,201 @@ +raw_json = $json_response; + $this->log = \Amazon\Debug\AmazonDebug::getLog(\Amazon\Debug\AmazonDebug::getId()); + $this->parseJsonResponse($json_response); + } + + /** + * @return array + */ + public function getLog(): array + { + return $this->log; + } + + /** + * @return string + */ + public function getId(): string + { + return $this->id; + } + + /** + * @return string + */ + public function getCreationRequestId(): string + { + return $this->creation_request_id; + } + + /** + * @return string + */ + public function getClaimCode(): string + { + return $this->claim_code; + } + + /** + * @return string + */ + public function getValue(): string + { + return $this->value; + } + + /** + * @return string + */ + public function getCurrency(): string + { + return $this->currency; + } + + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @return string + */ + public function getExpirationDate(): string + { + return $this->expiration_date; + } + + /** + * @return string + */ + public function getCardStatus(): string + { + return $this->card_status; + } + + + /** + * @return string + */ + public function getRawJson(): string + { + return json_encode($this->raw_json); + } + + /** + * @param array $json_response + * @return CreateResponse + */ + public function parseJsonResponse(array $json_response): self + { + if (!is_array($json_response)) { + throw new \RuntimeException('Response must be a scalar value'); + } + if (array_key_exists('gcId', $json_response)) { + $this->id = $json_response['gcId']; + } + if (array_key_exists('creationRequestId', $json_response)) { + $this->creation_request_id = $json_response['creationRequestId']; + } + if (array_key_exists('gcClaimCode', $json_response)) { + $this->claim_code = $json_response['gcClaimCode']; + } + if (array_key_exists('amount', $json_response['cardInfo']['value'])) { + $this->value = $json_response['cardInfo']['value']['amount']; + } + if (array_key_exists('currencyCode', $json_response['cardInfo']['value'])) { + $this->currency = $json_response['cardInfo']['value']['currencyCode']; + } + if (array_key_exists('gcExpirationDate', $json_response)) { + $this->expiration_date = $json_response['gcExpirationDate']; + } + if (array_key_exists('cardStatus', $json_response['cardInfo'])) { + $this->card_status = $json_response['cardInfo']['cardStatus']; + } + // SUCCESS, FAILURE, RESEND + if (array_key_exists('status', $json_response)) { + $this->status = $json_response['status']; + } + + return $this; + } +} + +// __END__ diff --git a/test/autoloader.php b/test/autoloader.php new file mode 100644 index 0000000..e48eca5 --- /dev/null +++ b/test/autoloader.php @@ -0,0 +1,63 @@ +"; + // set directory seperator (we need to replace from namespace) + $DS = DIRECTORY_SEPARATOR; + // base lib + $LIB = defined('LIB') ? LIB : '../src' . $DS; + // if lib is in path at the end, do not add lib again + // note that $LIB can have a directory seperator at the end + // strip that out before we do a match + $_LIB = rtrim($LIB, $DS); + if (!preg_match("|$_LIB$|", __DIR__)) { + $LIB .= $DS; + } else { + $LIB = ''; + } + // default path is unset + $path = false; + // set path on full dir + // if we have the namespace in the class, strip it out + $len = 0; + if (strpos($class, __NAMESPACE__) !== false) { + $len = strlen(__NAMESPACE__); + } + // set default extension + $extension = '.php'; + // set full include path + $path = __DIR__ . $DS . $LIB . substr($class, $len); + // replace namespace \ with dir sepeator + $path = str_replace('\\', $DS, $path) . $extension; + // print "(2) Class clean: $path
"; + // if path is set and a valid file + if ($path !== false && is_file($path)) { + // print "(3) Load Path: $path
"; + // we should sub that + // self::loadFile($path); + include $path; + return true; + } + return false; + } + // end class define + } + + spl_autoload_register('Autoloader\Autoload::load', true, true); +} // end check for already defined + +// __END__ diff --git a/test/aws_gift_card_tests.php b/test/aws_gift_card_tests.php new file mode 100644 index 0000000..e3b001e --- /dev/null +++ b/test/aws_gift_card_tests.php @@ -0,0 +1,141 @@ +Amazon Gift Card Incentives
"; + +// must have set +// endpoint/region: AWS_GIFT_CARD_ENDPOINT +// aws key: AWS_GIFT_CARD_KEY +// aws secret: AWS_GIFT_CARD_SECRET +// partner id: AWS_GIFT_CARD_PARTNER_ID +// optional +// currency: AWS_ICENTIVE_CURRENCY + +// as in .env +// AWS_GIFT_CARD_ENDPOINT.TEST +// AWS_GIFT_CARD_ENDPOINT.LIVE + +define('LOCATION', 'test'); +foreach ( + [ + 'AWS_GIFT_CARD_KEY', 'AWS_GIFT_CARD_SECRET', 'AWS_GIFT_CARD_PARTNER_ID', + 'AWS_GIFT_CARD_ENDPOINT', 'AWS_GIFT_CARD_CURRENCY', 'AWS_DEBUG' + ] as $key +) { + // + $_ENV[$key] = $_ENV[$key . '.' . strtoupper((LOCATION))] ?? $_ENV[$key] ?? ''; +} + +/* + ENDPOINTS: + +- remove '-gamma' for non sandox +WHERE URL REGION +North America https://agcod-v2-gamma.amazon.com us-east-1 + https://agcod-v2.amazon.com +(US, CA, MX) +Europe and Asia https://agcod-v2-eu-gamma.amazon.com eu-west-1 + https://agcod-v2-eu.amazon.com +(IT, ES, DE, FR, UK, TR, UAE, KSA, PL, NL, SE) +Far East https://agcod-v2-fe-gamma.amazon.com us-west-2 + https://agcod-v2-fe.amazon.com +(JP, AU, SG) + +CURRENCY +USD for US +EUR for EU +JPY for JP +CAD for CA +AUD for AU +TRY for TR +AED for UAE + +*/ + +// run tests +// print "checkMe Static:
" . print_r(Amazon\AmazonIncentives::checkMeStatic(), true) . "
"; + +$aws = new Amazon\AmazonIncentives(); +// $aws->createGiftCard(100); +print "checkMe:
" . print_r($aws->checkMe(), true) . "
"; +print "
"; + +// we should open log file to collect all creationRequestId/gcId +// so we can test and cancel + +// check balance +try { + $aws_test = Amazon\AmazonIncentives::make()->getAvailableFunds(); + print "AWS: getAvailableFunds:
" . print_r($aws_test, true) . "

"; +} catch (Exception $e) { + print "AWS: getAvailableFunds FAILURE [" . $e->getCode() . "]: " + . "
" . print_r(Amazon\AmazonIncentives::decodeExceptionMessage($e->getMessage()), true) . "

"; + exit; +}; +// print "LOG:
" . print_r($aws_test->getLog(), true) . "

"; +print "
"; + +// skip early for testing +// exit; + +/* +// create card +$value = 1000; +// we must be sure we pass FLOAT there +$aws_test = Amazon\AmazonIncentives::make()->buyGiftCard((float)$value); +print "AWS: buyGiftCard:
" . print_r($aws_test, true) . "

"; +$creation_request_id = $aws_test->getCreationRequestId(); +$gift_card_id = $aws_test->getId(); +$claim_code = $aws_test->getClaimCode(); +print "AWS creationRequestId: " . $creation_request_id . ", gcId: " . $gift_card_id . "
"; +print "AWS CLAIM CODE: " . $claim_code . "
"; +print "
"; + +// cancel card +$aws_test = Amazon\AmazonIncentives::make()->cancelGiftCard($creation_request_id, $gift_card_id); +print "AWS: buyGiftCard:
" . print_r($aws_test, true) . "

"; +print "
"; + */ + +// MOCK TEST +$value = 500; +$creation_id = 'F0000'; +$aws_test = Amazon\AmazonIncentives::make()->buyGiftCard((float)$value, $creation_id); +$creation_request_id = $aws_test->getCreationRequestId(); +$gift_card_id = $aws_test->getId(); +$claim_code = $aws_test->getClaimCode(); +print "AWS: MOCK: " . $creation_id . ": buyGiftCard:
" . print_r($aws_test, true) . "

"; +print "AWS creationRequestId: " . $creation_request_id . ", gcId: " . $gift_card_id . "
"; +print "AWS CLAIM CODE: " . $claim_code . "
"; +print "
"; + +$creation_id = 'F2005'; +try { + $aws_test = Amazon\AmazonIncentives::make()->buyGiftCard((float)$value, $creation_id); + $creation_request_id = $aws_test->getCreationRequestId(); + $gift_card_id = $aws_test->getId(); + $claim_code = $aws_test->getClaimCode(); + print "AWS: MOCK: " . $creation_id . ": buyGiftCard:
" . print_r($aws_test, true) . "

"; + print "AWS creationRequestId: " . $creation_request_id . ", gcId: " . $gift_card_id . "
"; + print "AWS CLAIM CODE: " . $claim_code . "
"; +} catch (Exception $e) { + print "AWS: MOCK: " . $creation_id . ": buyGiftCard: FAILURE [" . $e->getCode() . "]: " + . "
" . print_r(Amazon\AmazonIncentives::decodeExceptionMessage($e->getMessage()), true) . "

"; +} +print "
"; + +// ... should do all possible important mock tests + +// failed card (invalid data) +// double card + +// __END__ diff --git a/test/read_env_file.php b/test/read_env_file.php new file mode 100644 index 0000000..22f3e28 --- /dev/null +++ b/test/read_env_file.php @@ -0,0 +1,84 @@ + abort + if (!is_file($env_file_target)) { + $status = 3; + return $status; + } + // cannot open file -> abort + if (($fp = fopen($env_file_target, 'r')) === false) { + $status = 2; + return $status; + } + // set to readable but not yet any data loaded + $status = 1; + $block = false; + $var = ''; + while ($line = fgets($fp)) { + // main match for variable = value part + if (preg_match("/^\s*([\w_.]+)\s*=\s*((\"?).*)/", $line, $matches)) { + $var = $matches[1]; + $value = $matches[2]; + $quotes = $matches[3]; + // wirte only if env is not set yet, and write only the first time + if (empty($_ENV[$var])) { + if (!empty($quotes)) { + // match greedy for first to last so we move any " if there are + if (preg_match('/^"(.*[^\\\])"/U', $value, $matches)) { + $value = $matches[1]; + } else { + // this is a multi line + $block = true; + // first " in string remove + // add removed new line back because this is a multi line + $value = ltrim($value, '"') . PHP_EOL; + } + } + // if block is set, we strip line of slashes + $_ENV[$var] = $block === true ? stripslashes($value) : $value; + // set successful load + $status = 0; + } + } elseif ($block === true) { + // read line until there is a unescaped " + // this also strips everything after the last " + if (preg_match("/(.*[^\\\])\"/", $line, $matches)) { + $block = false; + // strip ending " and EVERYTHING that follows after that + $line = $matches[1]; + } + // strip line of slashes + $_ENV[$var] .= stripslashes($line); + } + } + fclose($fp); + return $status; +} + +// __END__