Skip to content

Instantly share code, notes, and snippets.

@mathpere
Created November 18, 2014 18:35
Show Gist options
  • Save mathpere/796231fadefba22d894d to your computer and use it in GitHub Desktop.
Save mathpere/796231fadefba22d894d to your computer and use it in GitHub Desktop.
PayZen with NodeJS
{
"payZen": {
"url": "https://secure.payzen.eu/vads-payment/",
"certificat": "XXXXXXXXX",
"vads_site_id": "YYYYYYYY",
"vads_version": "V2",
"vads_ctx_mode": "TEST"
}
}
var _ = require('lodash');
var moment = require('moment');
var validator = require('validator');
var async = require('async');
var PayZenTransactionId = require('./payZenTransactionId');
var S = require('string');
var payZen = require('./payZen');
var config = require('config');
// create PayZen request:
exports.payZenRequest = function (req, res, next) {
var user = req.user;
var cart = req.cart;
async.waterfall([
function getNewTransactionId(cb) {
PayZenTransactionId.getNewTransactionId(cb);
},
function createRequestParams(payZenTransactionId, cb) {
var params = {};
params.vads_version = config.payZen.vads_version;
params.vads_trans_date = moment.utc().format('YYYYMMDDHHmmss');
params.vads_ctx_mode = config.payZen.vads_ctx_mode;
params.vads_site_id = config.payZen.vads_site_id;
params.vads_page_action = cart.subscription ? 'REGISTER_PAY_SUBSCRIBE' /* = S5 */ : 'PAYMENT';
params.vads_action_mode = 'INTERACTIVE';
// TRANSACTION
params.vads_trans_id = S(payZenTransactionId.transactionId).padLeft(6, '0').s;
params.vads_amount = cart.subscription ? Math.round((cart.total - cart.subscription.price) * 100) : Math.round(cart.total * 100);
params.vads_currency = 978; // euro
params.vads_payment_config = 'SINGLE';
// SUBSCRIPTION
if (cart.subscription) {
var tomorrow = moment().add(1, 'days');
params.vads_sub_effect_date = tomorrow.format('YYYYMMDD');// subscription begins @ D+1
params.vads_sub_amount = Math.round(cart.subscription.price * 100);
params.vads_sub_currency = 978;
params.vads_sub_desc = 'RRULE:FREQ=MONTHLY;COUNT=' + cart.subscription.term + ';BYMONTHDAY=5';
}
// SHOP RETURN
params.vads_return_mode = 'GET';
params.vads_url_return = config.baseUrl + '/cart';
params.vads_url_error = config.baseUrl + '/cart?error=internal';
params.vads_url_referral = config.baseUrl + '/cart?error=referral';
params.vads_url_refused = config.baseUrl + '/cart?error=refused';
params.vads_url_success = config.baseUrl + '/cart?success=1';
params.vads_url_cancel = config.baseUrl + '/cart?cancel=1';
// ORDER
params.vads_order_id = cart.id;
//vads_order_info1
//vads_order_info2
//vads_order_info3
// CUSTOMER
params.vads_cust_email = user.email;
params.vads_cust_id = user.id;
params.vads_cust_last_name = user.lastName;
params.vads_cust_first_name = user.firstName;
params.vads_cust_title = user.gender === 'fr' ? 'Mr' : 'Mme';
// PAYMENT PAGE
params.vads_payment_cards = 'CB';
params.vads_available_languages = 'fr;en';
params.vads_language = req.locale;
// etc.
var signature = payZen.signRequest(params);
cb(null, _.assign(params, {signature: signature}));
},
function saveRequestParams(params, cb) {
cart.payZen.request.params = params;
cart.save(cb);
}
], function (err, cart) {
if (err) {
return res.status(400).send({message: 'Unknown error...'});
}
res.status(200).json(cart.payZen.request);
});
};
// Handle PayZen callback:
exports.payZenCallback = function (req, res, next) {
var signature = req.body.signature;
if (!payZen.verify(signature, req.body)) {
return res.status(404).send({message: 'Signature unverified'});
}
// do your stuff!...
};
var _ = require('lodash');
var crypto = require('crypto');
var config = require('config');
var S = require('string');
var prefix = 'vads_';
var separator = '+';
function signRequest(params, certificat) {
certificat = certificat || config.payZen.certificat;
var string = _(params)
.map(function (v, k) {
return [k, v];
})
.filter(function (it) {
return S(it[0]).startsWith(prefix);
})
.sortBy(function (it) {
return it[0];
})
.map(function (it) {
return it[1];
})
.value()
.concat(certificat)
.join(separator);
var shasum = crypto.createHash('sha1');
shasum.update(string);
return shasum.digest('hex');
}
function verify(signature, params, certificat) {
certificat = certificat || config.payZen.certificat;
var expectedSignature = signRequest(params, certificat);
return signature === expectedSignature;
}
exports.signRequest = signRequest;
exports.verify = verify;
var mongoose = require('mongoose');
var moment = require('moment');
var payZenTransactionIdSchema = new mongoose.Schema({
transactionId: {type: Number, default: 1},
transactionDate: {type: String} // yyyymmdd
});
payZenTransactionIdSchema.statics.getNewTransactionId = function (callback) {
var now = moment().format('YYYYMMDD');
this.findOneAndUpdate({transactionDate: now}, {$inc: {transactionId: 1}}, {'new': true, upsert: true}, callback);
};
module.exports = mongoose.model('PayZenTransactionId', payZenTransactionIdSchema);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment