node-payments
v0.1.7
Published
node-payments is a express based facade to multiple payment services.
Downloads
36
Maintainers
Readme
node-payments
Node-payments is a express based facade to multiple payment services.
The idea is an simple and inutive API to handle just simple single payments. It's als designed to add more payment services over time, but without changing the general API.
The service type is just one argument within the process.
For every provider the required messaging endpoint, like PayPal's IPN, will be attached to express. So everything you need is included.
Features
- A simple and equal API for multiple providers.
- Integrated messaging endpoints to verify the payments.
- A flexible payment-store to simply integrate it within your environment.
What it can't do
To hold it simple and equal over all providers it has only the option for single and simple payments. Batch payments, recurring subscriptions, etc. are not availible.
Currently applied services
Example
// configure express
var express = require( "express" );
var app = express();
app.use( express.urlencoded() );
// get and config the module
var Payments = require( "node-payments" );
// inject and reuse a existing express
var paymentConfig = { express: app, paymentStore: new Payments.RedisHashStore() }
var pymts = new Payments( paymentConfig );
// listen to events
// the event fired for a succesfull provider payment
pymts.on( "approved", function( res, payment ){
// use the express response object to generate the page after retuning from the providers page
res.send( "Thank you!" );
});
// the event fired for a canceld provider payment
pymts.on( "cancel", function( res, payment ){
// use the express response object to generate the page after a canceld payments by/within the providers page
res.send( "What a pity!" );
});
// the event fired for a successfull verify by a message service ( e.g. PayPal-IPN or ClickandBuy-MMS ).
pymts.on( "verfied", function( payment ){
console.log( "PAYMENT VERIFIED\"n", payment.valueOf() );
});
// the event on every change of a payment
pymts.on( "payment", function( type, payment ){
console.log( "PAYMENT ACTION: " + type "\"n", payment.valueOf() );
});
// listen for pay requests ( e.g. "www.mysite.com/pay/paypal"
app.get( "/pay/:provider/:cid", function( req, res ){
// Get thh service provider
pymts.provider( req.params.provider, function( err, provider ){
if( err ){
console.log( err );
res.send( "ERROR", 500 );
}
// create a payment instance
var payment = provider.create()
// set some parameters
payment.set({
amount: 41.99,
curreny: "EUR",
desc: "Imperial Star Destroyer",
// you can define your own attributes
my_custom_id: req.params.cid
});
payment.execute( function( err, link ){
if( err ){
console.log( err );
res.send( "ERROR", 500 );
}
// redirect to the providers login page
res.redirect( link );
});
});
});
// start express. Make sure you start listening after node-payments has been configured.
var _port = 8888;
console.log( "listen to", _port );
app.listen( _port );
Initialize
to initailize node-payments call new
with and put in your express.
new Payments( config )
###Config-Options:
- express (
Express
- optional; default = A internal express will be generated ): An existing express instance ( e.g.require( "express" )()
). - baseroute (
String
- optional; default =/payment/
): The basic route to generate the redirect url from the external providers. - redirprefix (
String
- recommended ): The host added infront of the baseroute. If not set it will try to guess it. But it recommended to set this configuration key. - providers (
Array
- optional default =[ "paypal", "clickandbuy" ]
): A list of availabel providers. - paypal (
Object
): PayPay pay configuration- endpoint (
String
, optional; default =https://api-3t.paypal.com/nvp
): The paypal endpoint. To use the Sandbox environment set this tohttps://api-3t.sandbox.paypal.com/nvp
- userid (
String
): Your PayPal mercant user id - password (
String
): Your PayPal mercant password - signature (
String
): Your PayPal mercant signature - application_id (
String
): Your PayPal mercant application_id. For the sandbox environment do not change this or use the defaultAPP-80W284485P519543T
. - receiver_email (
String
): Your PayPal mail adress - localcode (
String
, optional; default =DE
): The local code to use the correct language. Possible codes - linkTemplate (
String
, optional; default =https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=<%= token %>
): A template to translate the returned token to the redirect link. To use the Sandbox environment set this tohttps://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=<%= token %>
- endpoint (
- paypalipn (
Object
): PayPal IPN ( Instant Payment Notification ) configuration- receiverPath (
String
, optional; default =/ipn/paypal
): The IPN route added to your express. PayPay will send POST request to this route to verify your payments. You have to configure this within your PayPay account. - receiver_email (
String
, optional ): Usually you PayPal email adress. If set!= null
node-payments will check the reciever email within the IPN message against this value. If leftnull
no check will be performend.
- receiverPath (
- clickandbuy (
Object
): ClickandBuy pay configuration- endpoint (
String
, optional; default =https://api.clickandbuy.com/webservices/soap/pay_1_1_0/
): The ClickandBuy endpoint. To use the sandbox environment set this tohttps://api.clickandbuy-s1.com/webservices/soap/pay_1_1_0/
. - merchantid (
String
): Your ClickandBuy mercant id - projectid (
String
): Your ClickandBuy mercant projectid - cryptokey (
String
): Your ClickandBuy project cryptokey - localcode (
String
, optional; default =DE
): ISO 3166-1 alpha-2 country code.
- endpoint (
- clickandbuymms (
Object
): ClickandBuy MMS ( Merchant Message Service ) configuration- receiverPath (
String
, optional; default =/cab/clickandbuy
): The MMS route added to your express. ClickandBuy will send POST request to this route to verify your payments. You have to configure this within your ClickandBuy account. - cryptokey (
String
): Your ClickandBuy events cryptokey.
- receiverPath (
- defaultcurrency (
String
optional; default =EUR
): The default currency. - productionmode (
Boolean
optional; default =true
): If you set thisfalse
the system answers with200
for request from messaging services if the payment is not found. Otherwise it will answer with500
.
Methods
Payments Object
Payments.provider( name, callback )
Get a instance of a payment provider.
#####Arguments:
- email (
String
): The users email. - callback (
Function
): The callback method.
callback
arguments
- error (
Error
): An error ornull
if everthing is ok - provider (
Provider
): The instance the requested provider.
Payments.getPayment( pid, callback )
Get a instance of a payment object.
#####Arguments:
- pid (
String
): The payment id to get - callback (
Function
): The callback method.
callback
arguments
- error (
Error
): An error ornull
if everthing is ok - provider (
Payment
): The instance the requested payment.
Payments.createPayment( type [, data], callback )
Create a new Payment.
#####Arguments:
- type (
String
): The provider name. Has to be one ofconfig.providers
. - data (
Object
optional ): Initial payment data. This could also be done later by usingPayment.set( ... )
- callback (
Function
): The callback method.
callback
arguments
- error (
Error
): An error ornull
if everthing is ok - provider (
Payment
): A new instance of a payment.
Provider Object
Provider.create( [data] )
Create a new Payment
of this provider.
#####Arguments:
- data (
Object
optional ): Initial payment data. This could also be done later by usingPayment.set( ... )
Payment Object
Getters are marked with a G and Setters with a S
Payment.provider
G
( String
) Getter to read the provider name
Payment.amount
required G/S
( Number
) Setter/Getter to set and read the amount
Payment.desc
required G/S
( String
) Setter/Getter to set and read the payment's description
Payment.currency
G/S
( String
) Setter/Getter to set and read the currency
Payment.articleNumber
G/S
( String
) Setter/Getter to set and read the a optional article number.
Payment.quantity
G/S
( String
) Setter/Getter to set and read the a optional quantity.
Payment.transaction
G
( String
) Getter to read the unique transaction number per provider. Is also a Setter, but this schould only be used internaly
Payment.state
G
( String
) Getter to read the current unified state. Is also a Setter, but this schould only be used internaly
Payment.rawProviderState
G
( String
) Getter to read the current raw provider state. This is just a info field to show the not unified. Is also a Setter, but this schould only be used internaly
Payment.pay_id
G
( String
) Getter to read the providers pay id. This is just a info field. Is also a Setter, but this schould only be used internaly
Payment.payer_id
G
( String
) Getter to read the providers payer id. This is just a info field. Is also a Setter, but this schould only be done internaly
Payment.verified
G
( Boolean
) Getter with a flag witch will be true
if a messaging service like IPN has verified this payment. Is also a Setter, but this schould only be used internaly
Payment.data
G
( Object
) Getter to read the internal data. This will inculde all data above and the custom fields set by Payment.set()
Payment.get( key )
Get a internal value like one described as getter above or your defined custom fields
- key (
String
): Key to get
Returns
( Any
): The requested field
Payment.set( [key,] value )
Get a internal value like one described as getter above or your defined custom fields
- key (
String
): Key to set - value (
String|Object
): Value to set. You can also only pass a object to theset
and all keys within the object will be setted.
Returns
( Payment
): This is a chainable method
Payment.valueOf()
Identical to Payment.data
Returns
( Object
) Getter to read the internal data. This will inculde all data above and the custom fields set by Payment.set()
Payment.toString( [ format ] )
Will return Payment.data
as stringified JSON
- format (
Boolean
optional; default =false
): Do a nicer JSON formating.
Returns
( String
) Payment.data
as stringified JSON
Payment.persist( callback )
Write the payment by the PaymanetStore
to the DB, disk, ...
- callback (
Function
): The callback method.
callback
arguments
- error (
Error
): An error ornull
if everthing is ok
Payment.exec( callback )
Execute the payment and generate the payment link to let the user login with his credentials for the defined provider.
- callback (
Function
): The callback method.
callback
arguments
- error (
Error
): An error ornull
if everthing is ok - link (
String
): The link to redirect the user to the payment provider
Payment.cancel( callback )
Manually cancle the payment and set the state to cancled
- callback (
Function
): The callback method.
callback
arguments
- error (
Error
): An error ornull
if everthing is ok - self (
Payment
): The payment itself
PaymentStore
You can or should define your own payment store. Otherwise the system uses the default fleeting memory store witch will loose all the data on every restart of the script.
For a quick start you can use the ready RedisHashStore
.
Payments = require( "../." )
new Payments( paymentStore: new Payments.RedisHashStore( { hkey: "nodepaymentexample", host: "localhost", port: 6379 } ) )
A PaymentStore has to implement the methods .connect()
, .get( pid, callback )
, .set( payment, callback )
, .destroy( payment, callback )
.
The following code describes a simplified solution:
var EventEmitter = require('events').EventEmitter;
var YourDBConnector = require( "your-db" );
var db = new YourDBConnector();
module.exports = function(){
function MyPaymentStore(){
this.connected = false;
}
// extend the event emitter methods
MyPaymentStore.prototype.emit = EventEmitter.emit;
MyPaymentStore.prototype.on = EventEmitter.on;
MyPaymentStore.prototype.once = EventEmitter.once;
MyPaymentStore.prototype.removeListener = EventEmitter.removeListener;
// connect method called on start to connect to your db. Just call `this.connected = true;this.emit("connect");` if you don't need to connect.
MyPaymentStore.prototype.connect = function() {
db.connect( function(){
this.connected = true;
this.emit("connect");
} );
};
// get data of a single payment
MyPaymentStore.prototype.get = function( pid, callback ) {
process.nextTick(function() {
db.get( pid, function( err, data ){
if( err ){ return callback( err ); }
callback( null, data );
} );
});
};
// set data of a single payment
MyPaymentStore.prototype.set = function( payment, callback ) {
process.nextTick(function() {
db.set( payment.id, payment.valueOf(), function( err ){
if( err ){ return callback( err ); }
callback( null );
} );
});
};
// delete a single payment
MyPaymentStore.prototype.destroy = function( payment, callback ) {
process.nextTick(function() {
db.destroy( payment.id, function( err ){
if( err ){ return callback( err ); }
callback( null );
} );
});
};
return MyPaymentStore;
};
Attension
Paypal IPN encoding
The Paypal IPN send's the IPN messages encoded as windows-1251
. Usually Node is working with utf-8
and the IPN receiver can not verify the messages succefully.
After doing some search i found this article. So you have to change this within the paypal settings, but the Settings are no longer availibel via the GUI so use this link https://www.paypal.com/ie/cgi-bin/webscr?cmd=_profile-language-encoding.
TODO's
- A
sandbox
config setting to switch beween the sandbox and live environments. - Finalize the
paypalrest
provider. It's basically done, but the problem is it's not availible in Europe. So i can't test it live and seriously. It you want to use it addpaypalrest
to theconfig.providers
list.
Ideas
- A logging store, similar to the payment store solution, to save all incomming messages with a log and be able to retrace all happening events.
Release History
|Version|Date|Description| |:--:|:--:|:--| |v0.1.7|2016-05-24|Fixed npm versions to match the latest development date in dez. 2013| |v0.1.5|2013-12-09|Added npm keywords and used a better package description. Removed some console.log's.| |v0.1.4|2013-12-04|Fixed loading of redis in redishashstore if not used.| |v0.1.3|2013-12-04|Added detailed docs and some optimizations| |v0.1.2|2013-12-03|First offical working beta|
Work in progress
node-payments
is work in progress. Your ideas, suggestions etc. are very welcome.
Related Projects
|Name|Description| |:--|:--| |tcs_node_auth|Authentication module to handle login and register with a integrated mail double-opt-in logic.| |redis-sessions|The redis session module this middleware module is based on| |tcs_node_mail_client|Module to simply send mails by using the TCS mail Webservice (node-tcs-de)|
The MIT License (MIT)
Copyright © 2013 Mathias Peter, http://www.tcs.de
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.