0

I have the following code below for clover payment api and although the code works perfectly, I do not get a response back when I call the api from postman. I know this is because of the multiple requests in the service and I tried to find a cleaner way to do it but keep failing to get it to work. I am trying to send back the final response which is the response of the request in the postPayment() function. Any help would be appreciated.

my service code is:

const db = require('../_helpers/db');
const crypto = require('crypto');
const request = require("request-promise");


module.exports = {
    getAll
};

var targetEnv = 'https://sandbox.dev.clover.com/v2/merchant/';
var cardNumber = '6011361000006668';

async function getAll(data) {
  var url = targetEnv + data.merchant_id + '/pay/key';

  var options = {
    url: url,
    method: 'GET',
    headers: {
      Authorization: 'Bearer ' + data.api_token
    }
  };

  request(options, (error, response, body) => {
    if (!error && response.statusCode === 200) {
      console.log('getAll ' +data);
      processEncryption(JSON.parse(body), JSON.stringify(data));
    }
  });
}

// Process the encryption information received by the pay endpoint.
function processEncryption(jsonResponse, data) {
  console.log('processEncryption ' +data);
  var prefix = jsonResponse['prefix'];
  var pem = jsonResponse['pem'];

  // create a cipher from the RSA key and use it to encrypt the card number, prepended with the prefix from GET /v2/merchant/{mId}/pay/key
  var encrypted = crypto.publicEncrypt(pem, Buffer(prefix + cardNumber));

  // Base64 encode the resulting encrypted data into a string to Clover as the 'cardEncrypted' property.
  var cardEncrypted = new Buffer(encrypted).toString('base64');

  return postPayment(cardEncrypted, data);
}

// Post the payment to the pay endpoint with the encrypted card information.
async function postPayment(cardEncrypted, body) {
  // POST to /v2/merchant/{mId}/pay
  console.log('mid ' +JSON.parse(body));
  var posturl = targetEnv + '9ZQTAJSQKZ391/pay';
  var postData = {
    "orderId": "4N3RBF33EBEGT",
    "currency": "usd",
    "amount": 2,
    "tipAmount": 0,
    "taxAmount": 0,
    "expMonth": 12,
    "cvv": 123,
    "expYear": 2018,
    "cardEncrypted": cardEncrypted,
    "last4": 6668,
    "first6": 601136,
    "streetAddress": "123 Fake street",
    "zip": "94080",
    "merchant_id": "9ZQTAJSQKZ391",
    "order_id": "4N3RBF33EBEGT",
    "api_token": "4792a281-38a9-868d-b33d-e36ecbad66f5"
  }

  var options = {
    url: posturl,
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + "4792a281-38a9-868d-b33d-e36ecbad66f5",
    },
    json: postData
  };

   request(options, (error, response, body) => {
    if (!error && response.statusCode === 200) {
      //console.log(response);  
      return response;   <---- this response is what i need to show in postman
    }
  });
   console.log(response);
}

my controller is:

const express = require('express');
const router = express.Router();
const tableOrderService = require('./cloverPayment.service');

// routes
router.post('/getAll', getAll);


module.exports = router;


function getAll(req, res, next) {
    tableOrderService.getAll(req.body)
        .then(users => res.json(users))
        .catch(err => next(err));
}
z123
  • 193
  • 1
  • 15
  • You have to pass `res` into both `processEncryption()` and `postPayment()` as an argument and then use `res.send(...)` to send your final response from inside the `request()` callback in `postPayment()`. And, you have multiple places where you need to do proper error handling too by sending an error response. You cannot return the value directly like you are trying to be it's asynchronous and you're just returning into your callback as the function has long since previously returned already before the value was even available. – jfriend00 Jan 14 '21 at 08:15
  • @jfriend00 Thanks for the reply, it does not work. When I try passing res it gives an error. can you provide an example? – z123 Jan 14 '21 at 21:01

1 Answers1

1

Your asynchronous functions getAll() and postPayment() are not properly returning an asynchronous value (either via callback or promise).

I'd suggest converting everything to promises and returning a promise from getAll() and from postPayment(). And, since converting to promises, I'd remove the deprecated request-promise library in favor of the got() library. Then, you can call getAll(), get a promise back and use either the resolved value or the rejection to send your response from the actual request handler:

const db = require('../_helpers/db');
const crypto = require('crypto');
const got = require('got');

module.exports = {
    getAll
};

var targetEnv = 'https://sandbox.dev.clover.com/v2/merchant/';
var cardNumber = '6011361000006668';

async function getAll(data) {
    console.log('getAll ', data);
    const url = targetEnv + data.merchant_id + '/pay/key';

    const options = {
        url: url,
        method: 'GET',
        headers: {
            Authorization: 'Bearer ' + data.api_token
        }
    };
    const response = await got(options);
    return processEncryption(response, data);
}

// Process the encryption information received by the pay endpoint.
function processEncryption(jsonResponse, data) {
    console.log('processEncryption ' + data);
    const prefix = jsonResponse.prefix;
    const pem = jsonResponse.pem;

    // create a cipher from the RSA key and use it to encrypt the card number, prepended with the prefix from GET /v2/merchant/{mId}/pay/key
    const encrypted = crypto.publicEncrypt(pem, Buffer(prefix + cardNumber));

    // Base64 encode the resulting encrypted data into a string to Clover as the 'cardEncrypted' property.
    const cardEncrypted = Buffer.from(encrypted).toString('base64');
    return postPayment(cardEncrypted, data);
}

// Post the payment to the pay endpoint with the encrypted card information.
function postPayment(cardEncrypted, body) {
    // POST to /v2/merchant/{mId}/pay
    console.log('mid ', body);
    const posturl = targetEnv + '9ZQTAJSQKZ391/pay';
    const postData = {
        "orderId": "4N3RBF33EBEGT",
        "currency": "usd",
        "amount": 2,
        "tipAmount": 0,
        "taxAmount": 0,
        "expMonth": 12,
        "cvv": 123,
        "expYear": 2018,
        "cardEncrypted": cardEncrypted,
        "last4": 6668,
        "first6": 601136,
        "streetAddress": "123 Fake street",
        "zip": "94080",
        "merchant_id": "9ZQTAJSQKZ391",
        "order_id": "4N3RBF33EBEGT",
        "api_token": "4792a281-38a9-868d-b33d-e36ecbad66f5"
    }

    const options = {
        url: posturl,
        method: 'POST',
        headers: {
            'Authorization': 'Bearer ' + "4792a281-38a9-868d-b33d-e36ecbad66f5",
        },
        json: postData
    };

    return got(options);
}

And, then your controller:

const express = require('express');
const router = express.Router();
const tableOrderService = require('./cloverPayment.service');

// routes
router.post('/getAll', (req, res) => {
    tableOrderService.getAll(req.body)
        .then(users => res.json(users))
        .catch(err => next(err));
});

module.exports = router;
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks a lot, your example really clarified a lot of stuff and i finally got it working. – z123 Jan 14 '21 at 23:10