From b0d24c68144b7833b98b9ef1f91356fc2dcae5ef Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Thu, 19 May 2016 17:29:24 -0300 Subject: [PATCH] Handle errors. Cancel gift card --- public/views/amazon.html | 7 +- public/views/buyAmazon.html | 33 ++++- public/views/modals/amazon-card-details.html | 71 ++++++++-- src/js/controllers/amazon.js | 56 +++++++- src/js/controllers/buyAmazon.js | 5 +- src/js/services/amazonService.js | 131 ++++++++++++------- 6 files changed, 239 insertions(+), 64 deletions(-) diff --git a/public/views/amazon.html b/public/views/amazon.html index cd57f6ff9..0b62b612d 100644 --- a/public/views/amazon.html +++ b/public/views/amazon.html @@ -40,7 +40,7 @@
-
+
Amazon Gift Card
@@ -60,8 +60,9 @@ {{item.cardInfo.value.amount | currency : item.cardInfo.value.currencyCode + ' ' : 2}}
- Error - {{item.date * 1000 | amTimeAgo}} + Error + Resend is required + {{item.date * 1000 | amTimeAgo}}
diff --git a/public/views/buyAmazon.html b/public/views/buyAmazon.html index d049109ec..348587901 100644 --- a/public/views/buyAmazon.html +++ b/public/views/buyAmazon.html @@ -27,6 +27,17 @@ {{buy.error}} +
+ There was an error when trying to buy gift card, but the funds were sent to BitPay Invoice. Please, contact + BitPay to refund your bitcoin +
+ Amount: {{buy.errorInfo.amount}} {{buy.errorInfo.currencyCode}}
+ BitPay Invoice ID: {{buy.errorInfo.bitpayInvoiceId}}. +
+ +
@@ -73,7 +84,27 @@
-
+
+

Amazon.com Gift Card could not be created

+
+ + There was an error when trying to create the Amazon.com Gift Card. Status: {{buy.giftCard.status}} + +
+
+ + This is a temporary/recoverable system failure that can be + resolved retrying the request from your list of cards + + + This failure could not be recoverable. Request your refund from your list of cards + + +
+
+

Gift card ready to redeem!

diff --git a/public/views/modals/amazon-card-details.html b/public/views/modals/amazon-card-details.html index ddf25724f..b8ae6ae90 100644 --- a/public/views/modals/amazon-card-details.html +++ b/public/views/modals/amazon-card-details.html @@ -17,28 +17,55 @@ ng-swipe-right="cancel()">
- Amazon + Amazon
{{card.cardInfo.value.amount | currency : card.cardInfo.value.currencyCode + ' ' : 2}}
+
+ + {{error}} + +
+ +
+
+
+ There was a temporary/recoverable system failure that can be resolved by retrying the request +
+ +
+
+ There was a failure to the create gift card that could not be recoverable. Please, contact BitPay to refund your bitcoin +
+
+
    -
  • +
  • Claim code {{card.gcClaimCode}}
  • - Created at - {{card.date * 1000 | amDateFormat:'MM/DD/YYYY HH:mm a'}} + Card status + Fulfilled + Refunded to purchaser + Expired
  • - Status - Completed - Pending - Error + Created at + {{card.date * 1000 | amDateFormat:'MM/DD/YYYY HH:mm a'}} +
  • +
  • + Creation status + Success + Resend is required + Error + Refunded
  • @@ -47,5 +74,33 @@
+
+
+

+ This action will remove the gift card +

+ +
+
+ +
+
+

+ This action will cancel the gift card +

+ +
+
+
diff --git a/src/js/controllers/amazon.js b/src/js/controllers/amazon.js index 0149c11aa..df90a6373 100644 --- a/src/js/controllers/amazon.js +++ b/src/js/controllers/amazon.js @@ -15,7 +15,6 @@ angular.module('copayApp.controllers').controller('amazonController', return; } self.giftCards = gcds; - }); }; @@ -26,8 +25,55 @@ angular.module('copayApp.controllers').controller('amazonController', var ModalInstanceCtrl = function($scope, $modalInstance) { $scope.card = card; + $scope.cancelGiftCard = function() { + $scope.refresh = true; + var dataSrc = { + creationRequestId: $scope.card.creationRequestId, + gcId: $scope.card.gcId, + bitpayInvoiceId: $scope.card.bitpayInvoiceId, + bitpayInvoiceUrl: $scope.card.bitpayInvoiceUrl, + date: $scope.card.date + }; + $scope.loading = true; + amazonService.cancelGiftCard(dataSrc, function(err, data) { + $scope.loading = null; + if (err || data.status != 'SUCCESS') { + $scope.error = err || data.status; + return; + } + $scope.refreshGiftCard(); + }); + }; + + $scope.remove = function() { + amazonService.saveGiftCard($scope.card, {remove: true}, function(err) { + $modalInstance.close(true); + }); + }; + + $scope.refreshGiftCard = function() { + $scope.refresh = true; + var dataSrc = { + creationRequestId: $scope.card.creationRequestId, + amount: $scope.card.cardInfo.value.amount, + currencyCode: $scope.card.cardInfo.value.currencyCode, + bitpayInvoiceId: $scope.card.bitpayInvoiceId, + bitpayInvoiceUrl: $scope.card.bitpayInvoiceUrl, + date: $scope.card.date + }; + $scope.loading = true; + amazonService.createGiftCard(dataSrc, function(err, data) { + $scope.loading = null; + if (err) { + $scope.error = err; + return; + } + $scope.card = data; + }); + }; + $scope.cancel = lodash.debounce(function() { - $modalInstance.dismiss('cancel'); + $modalInstance.close($scope.refresh); }, 0, 1000); }; @@ -39,7 +85,7 @@ angular.module('copayApp.controllers').controller('amazonController', }); var disableCloseModal = $rootScope.$on('closeModal', function() { - modalInstance.dismiss('cancel'); + modalInstance.close($scope.refresh); }); modalInstance.result.finally(function() { @@ -48,6 +94,10 @@ angular.module('copayApp.controllers').controller('amazonController', var m = angular.element(document.getElementsByClassName('reveal-modal')); m.addClass(animationService.modalAnimated.slideOutRight); }); + + modalInstance.result.then(function(refresh) { + if (refresh) self.init(); + }, function() {}); }; }); diff --git a/src/js/controllers/buyAmazon.js b/src/js/controllers/buyAmazon.js index a4e2da7b8..074fe04af 100644 --- a/src/js/controllers/buyAmazon.js +++ b/src/js/controllers/buyAmazon.js @@ -45,11 +45,12 @@ angular.module('copayApp.controllers').controller('buyAmazonController', }); } catch (e) { $log.debug(e); - }; + }; }; $scope.openWalletsModal = function(wallets) { self.error = null; + self.errorInfo = null; var ModalInstanceCtrl = function($scope, $modalInstance) { $scope.type = 'SELL'; $scope.wallets = wallets; @@ -104,6 +105,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', this.createTx = function() { self.error = null; + self.errorInfo = null; var currency_code = configService.getSync().amazon.testnet ? window.amazon_sandbox_currency_code : window.amazon_currency_code; var dataSrc = { @@ -178,6 +180,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', self.loading = null; if (err) { self.error = err; + self.errorInfo = gift; return; } self.giftCard = giftCard; diff --git a/src/js/services/amazonService.js b/src/js/services/amazonService.js index b32411a49..d904a5ef8 100644 --- a/src/js/services/amazonService.js +++ b/src/js/services/amazonService.js @@ -43,6 +43,52 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo return kSigning; } + + var _getHeaders = function(data, method, endpoint, amz_target) { + var content_type = 'application/json'; + var accept = 'application/json'; + var amz_date = moment.utc().format('YYYYMMDD[T]HHmmss[Z]'); + var date_stamp = moment.utc().format('YYYYMMDD'); + var canonical_querystring = ''; + + /************* TASK 1: CREATE A CANONICAL REQUEST *************/ + + var canonical_headers = + 'accept:' + accept + '\n' + + 'content-type:' + content_type + '\n' + + 'host:' + credentials.AMAZON_ENDPOINT.replace('https://', '') + '\n' + + 'x-amz-date:' + amz_date + '\n' + + 'x-amz-target:' + amz_target + '\n'; + + var signed_headers = 'accept;content-type;host;x-amz-date;x-amz-target'; + data = JSON.stringify(data); + var payload_hash = CryptoJS.SHA256(data).toString(CryptoJS.enc.Hex); + var canonical_request = method + '\n' + endpoint + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash; + + /************* TASK 2: CREATE THE STRING TO SIGN *************/ + + var algorithm = 'AWS4-HMAC-SHA256'; + var credential_scope = date_stamp + '/' + credentials.AMAZON_REGION + '/' + credentials.AMAZON_SERVICE_NAME + '/' + 'aws4_request'; + var hashed_canonical_request = CryptoJS.SHA256(canonical_request).toString(CryptoJS.enc.Hex); + var string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashed_canonical_request; + + /************* TASK 3: CALCULATE THE SIGNATURE *************/ + + var signing_key = _getSignatureKey(); + var signature = CryptoJS.HmacSHA256(string_to_sign, signing_key).toString(CryptoJS.enc.Hex) + var authorization_header = algorithm + ' ' + 'Credential=' + credentials.AMAZON_ACCESS_KEY + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature; + + /************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************/ + + return { + 'Content-Type': content_type, + 'Accept': accept, + 'X-Amz-Date': amz_date, + 'X-Amz-Target': amz_target, + 'Authorization': authorization_header + }; + }; + var _getBitPay = function(endpoint) { return { method: 'GET', @@ -125,7 +171,7 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo root.createGiftCard = function(dataSrc, cb) { var sandbox = credentials.AMAZON_SANDBOX ? 'T' : 'P'; // T: test - P: production var now = moment().unix(); - var requestId = credentials.AMAZON_PARTNER_ID + sandbox + now; + var requestId = dataSrc.creationRequestId || credentials.AMAZON_PARTNER_ID + sandbox + now; var data = { 'creationRequestId': requestId, @@ -136,66 +182,55 @@ angular.module('copayApp.services').factory('amazonService', function($http, $lo } }; - var content_type = 'application/json'; - var accept = 'application/json'; - var amz_date = moment.utc().format('YYYYMMDD[T]HHmmss[Z]'); - var date_stamp = moment.utc().format('YYYYMMDD'); + var method = 'POST'; + var endpoint = '/CreateGiftCard'; var amz_target = 'com.amazonaws.agcod.AGCODService.CreateGiftCard'; - var canonical_querystring = ''; - /************* TASK 1: CREATE A CANONICAL REQUEST *************/ - - var canonical_headers = - 'accept:' + accept + '\n' + - 'content-type:' + content_type + '\n' + - 'host:' + credentials.AMAZON_ENDPOINT.replace('https://', '') + '\n' + - 'x-amz-date:' + amz_date + '\n' + - 'x-amz-target:' + amz_target + '\n'; - - var signed_headers = 'accept;content-type;host;x-amz-date;x-amz-target'; - data = JSON.stringify(data); - var payload_hash = CryptoJS.SHA256(data).toString(CryptoJS.enc.Hex); - var canonical_request = 'POST' + '\n' + '/CreateGiftCard' + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash; - - /************* TASK 2: CREATE THE STRING TO SIGN *************/ - - var algorithm = 'AWS4-HMAC-SHA256'; - var credential_scope = date_stamp + '/' + credentials.AMAZON_REGION + '/' + credentials.AMAZON_SERVICE_NAME + '/' + 'aws4_request'; - var hashed_canonical_request = CryptoJS.SHA256(canonical_request).toString(CryptoJS.enc.Hex); - var string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashed_canonical_request; - - /************* TASK 3: CALCULATE THE SIGNATURE *************/ - - var signing_key = _getSignatureKey(); - var signature = CryptoJS.HmacSHA256(string_to_sign, signing_key).toString(CryptoJS.enc.Hex) - var authorization_header = algorithm + ' ' + 'Credential=' + credentials.AMAZON_ACCESS_KEY + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature; - - /************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************/ - - var headers = { - 'Content-Type': content_type, - 'Accept': accept, - 'X-Amz-Date': amz_date, - 'X-Amz-Target': amz_target, - 'Authorization': authorization_header - }; + var headers = _getHeaders(data, method, endpoint, amz_target); $http({ - 'method': 'POST', - 'url': credentials.AMAZON_ENDPOINT + '/CreateGiftCard', - 'data': data, + 'method': method, + 'url': credentials.AMAZON_ENDPOINT + endpoint, + 'data': JSON.stringify(data), 'headers': headers }).then(function(data) { - $log.info('Amazon Create Gift Card: SUCCESS'); + $log.info('Amazon.com Gift Card Create/Update: SUCCESS'); var newData = data.data; newData['bitpayInvoiceId'] = dataSrc.bitpayInvoiceId; newData['bitpayInvoiceUrl'] = dataSrc.bitpayInvoiceUrl; - newData['date'] = now; + newData['date'] = dataSrc.date || now; root.saveGiftCard(newData, null, function(err) { return cb(null, newData); }); }, function(data) { - $log.error('Amazon Create Gift Card: ERROR ' + data.statusText); + $log.error('Amazon.com Gift Card Create/Update: ERROR ' + data.statusText); + return cb(data.statusText); + }); + }; + + root.cancelGiftCard = function(dataSrc, cb) { + var data = { + 'creationRequestId': dataSrc.creationRequestId, + 'partnerId': credentials.AMAZON_PARTNER_ID, + 'gcId': dataSrc.gcId, + }; + + var method = 'POST'; + var endpoint = '/CancelGiftCard'; + var amz_target = 'com.amazonaws.agcod.AGCODService.CancelGiftCard'; + + var headers = _getHeaders(data, method, endpoint, amz_target); + + $http({ + 'method': method, + 'url': credentials.AMAZON_ENDPOINT + endpoint, + 'data': JSON.stringify(data), + 'headers': headers + }).then(function(data) { + $log.info('Amazon.com Gift Card Cancel: SUCCESS'); + return cb(null, data.data); + }, function(data) { + $log.error('Amazon.com Gift Card Cancel: ERROR ' + data.statusText); return cb(data.statusText); }); };