Skip to content

Commit

Permalink
Added Verifone payments
Browse files Browse the repository at this point in the history
  • Loading branch information
mrvautin committed Oct 30, 2021
1 parent fa4e61f commit 3197d38
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 1 deletion.
9 changes: 9 additions & 0 deletions config/payment/config/verifone.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"description": "Card payment",
"currency": "USD",
"userId": "test_this_is_not_real",
"apiKey": "test_this_is_not_real",
"baseUrl": "https://test-gsc.verifone.cloud",
"entityId": "test_this_is_not_real",
"paymentContract": "test_this_is_not_real"
}
35 changes: 35 additions & 0 deletions config/payment/schema/verifone.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"properties": {
"description": {
"type": "string"
},
"currency": {
"type": "string"
},
"userId": {
"type": "string"
},
"apiKey": {
"type": "string"
},
"baseUrl": {
"type": "string"
},
"entityId": {
"type": "string"
},
"paymentContract": {
"type": "string"
}
},
"required": [
"description",
"currency",
"userId",
"apiKey",
"baseUrl",
"entityId",
"paymentContract"
],
"additionalProperties": false
}
4 changes: 4 additions & 0 deletions config/settingsSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@
{
"type": "string",
"enum": [ "zip"]
},
{
"type": "string",
"enum": [ "verifone"]
}
]
}
Expand Down
53 changes: 53 additions & 0 deletions lib/payment-common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const got = require('got');
const numeral = require('numeral');
const { getPaymentConfig } = require('./config');

const setupVerifone = async(req) => {
const config = req.app.config;
const paymentConfig = getPaymentConfig('verifone');
const base64Auth = Buffer.from(`${paymentConfig.userId}:${paymentConfig.apiKey}`).toString('base64');

// Create the payload
const payload = {
entity_id: paymentConfig.entityId,
currency_code: paymentConfig.currency,
amount: numeral(req.session.totalCartAmount).format('0.00').replace('.', ''),
configurations: {
card: {
payment_contract_id: paymentConfig.paymentContract
}
},
interaction_type: 'IFRAME',
return_url: `${config.baseUrl}/verifone/checkout_return`
};

let setupResponse;
try{
setupResponse = await got.post(`${paymentConfig.baseUrl}/oidc/checkout-service/v2/checkout`, {
json: payload,
headers: {
'content-type': 'application/json',
Accept: 'application/json',
Authorization: `Basic ${base64Auth}`
},
rejectUnauthorized: false
});

// Parse the response
setupResponse = JSON.parse(setupResponse.body);

// Set our Checkout variables
return {
id: setupResponse.id,
url: setupResponse.url
};
}catch(ex){
console.log('ex', ex);
console.log('payload', payload);
return {};
}
};

module.exports = {
setupVerifone
};
150 changes: 150 additions & 0 deletions lib/payments/verifone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
const express = require('express');
const { indexOrders } = require('../indexing');
const { getId, sendEmail, getEmailTemplate } = require('../common');
const { getPaymentConfig } = require('../config');
const { emptyCart } = require('../cart');
const got = require('got');
const router = express.Router();

// The homepage of the site
router.get('/checkout_return', async (req, res, next) => {
const db = req.app.db;
const config = req.app.config;
const paymentConfig = getPaymentConfig('verifone');
const base64Auth = Buffer.from(`${paymentConfig.userId}:${paymentConfig.apiKey}`).toString('base64');

// Get checkoutid from session
const checkoutId = req.session.verifoneCheckout;

// Remove checkout from session
delete req.session.verifoneCheckout;

// Grab the checkout and the transaction
let checkoutResponse;
let transactionResponse;
try{
checkoutResponse = await got.get(`${paymentConfig.baseUrl}/oidc/checkout-service/v2/checkout/${checkoutId}`, {
headers: {
'content-type': 'application/json',
Accept: 'application/json',
Authorization: `Basic ${base64Auth}`
},
rejectUnauthorized: false
});

// Parse the response
checkoutResponse = JSON.parse(checkoutResponse.body);

transactionResponse = await got.get(`${paymentConfig.baseUrl}/oidc/api/v2/transaction/${checkoutResponse.transaction_id}`, {
headers: {
'content-type': 'application/json',
Accept: 'application/json',
Authorization: `Basic ${base64Auth}`
},
rejectUnauthorized: false
});

// Parse the response
transactionResponse = JSON.parse(transactionResponse.body);

// order status if approved
let orderStatus = 'Paid';
if(transactionResponse && transactionResponse.status !== 'SALE AUTHORISED'){
console.log('Declined response payload', checkoutResponse);
orderStatus = 'Declined';
}

// Set the transactionid
const transactionId = checkoutResponse.transaction_id;

const orderDoc = {
orderPaymentId: transactionId,
orderPaymentGateway: 'Verifone',
orderPaymentMessage: `${transactionResponse.reason_code} - ${transactionResponse.status}`,
orderTotal: req.session.totalCartAmount,
orderShipping: req.session.totalCartShipping,
orderItemCount: req.session.totalCartItems,
orderProductCount: req.session.totalCartProducts,
orderCustomer: getId(req.session.customerId),
orderEmail: req.session.customerEmail,
orderCompany: req.session.customerCompany,
orderFirstname: req.session.customerFirstname,
orderLastname: req.session.customerLastname,
orderAddr1: req.session.customerAddress1,
orderAddr2: req.session.customerAddress2,
orderCountry: req.session.customerCountry,
orderState: req.session.customerState,
orderPostcode: req.session.customerPostcode,
orderPhoneNumber: req.session.customerPhone,
orderComment: req.session.orderComment,
orderStatus: orderStatus,
orderDate: new Date(),
orderProducts: req.session.cart,
orderType: 'Single'
};

// insert order into DB
try{
const newDoc = await db.orders.insertOne(orderDoc);

// get the new ID
const newId = newDoc.insertedId;

// add to lunr index
indexOrders(req.app)
.then(() => {
// if approved, send email etc
if(orderStatus === 'Paid'){
// set the results
req.session.messageType = 'success';
req.session.message = 'Your payment was successfully completed';
req.session.paymentEmailAddr = newDoc.ops[0].orderEmail;
req.session.paymentApproved = true;
req.session.paymentDetails = `<p><strong>Order ID: </strong>${newId}</p>
<p><strong>Transaction ID: </strong>${orderDoc.orderPaymentId}</p>`;

// set payment results for email
const paymentResults = {
message: req.session.message,
messageType: req.session.messageType,
paymentEmailAddr: req.session.paymentEmailAddr,
paymentApproved: true,
paymentDetails: req.session.paymentDetails
};

// clear the cart
if(req.session.cart){
emptyCart(req, res, 'function');
}

// send the email with the response
// TODO: Should fix this to properly handle result
sendEmail(req.session.paymentEmailAddr, `Your payment with ${config.cartTitle}`, getEmailTemplate(paymentResults));

// redirect to outcome
res.redirect(`/payment/${newId}`);
}else{
// redirect to failure
req.session.messageType = 'danger';
req.session.message = 'Your payment has declined. Please try again';
req.session.paymentApproved = false;
req.session.paymentDetails = `<p><strong>Order ID: </strong>${newId}
</p><p><strong>Transaction ID: </strong> ${transactionId}</p>`;
res.redirect(`/payment/${newId}`);
}
});
}catch(ex){
console.log('Error getting payment response', ex);
res.status(400).json({ err: 'Your payment has declined. Please try again' });
}
}catch(ex){
console.info('Exception processing payment', ex);
req.session.messageType = 'danger';
req.session.message = 'Your payment has declined. Please try again';
req.session.paymentApproved = false;
req.session.paymentDetails = '';
res.redirect('/checkout/payment');
}
});

module.exports = router;
4 changes: 4 additions & 0 deletions public/stylesheets/less/style.less
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,10 @@ a {
color: #95a5a6;
}

iframe {
border:none;
}

@media only screen and (min-width: 768px){
.pushy {
width: 700px;
Expand Down
3 changes: 3 additions & 0 deletions public/stylesheets/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,9 @@ a {
.help-block {
color: #95a5a6;
}
iframe {
border: none;
}
@media only screen and (min-width: 768px) {
.pushy {
width: 700px;
Expand Down
Loading

0 comments on commit 3197d38

Please sign in to comment.