mirror of
https://github.com/janishutz/libreevent.git
synced 2025-11-25 13:24:24 +00:00
add payrexx as payment provider
This commit is contained in:
@@ -4,28 +4,7 @@ All payment gateway integration plugins have to be in their own folders. This fo
|
||||
You will also need to add documentation for the user to set up the payment gateway. Read on below to find out how.
|
||||
|
||||
## Setting up the routes.js file
|
||||
In the routes.js file you should have at least the following code:
|
||||
|
||||
```
|
||||
module.exports = ( app, settings ) => {
|
||||
app.post( '/payments/prepare', ( req, res ) => {
|
||||
|
||||
} );
|
||||
|
||||
app.get( '/payments/status', ( request, response ) => {
|
||||
response.writeHead( 200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive',
|
||||
} );
|
||||
response.status( 200 );
|
||||
response.flushHeaders();
|
||||
response.write( 'data: connected\n\n' );
|
||||
} );
|
||||
}
|
||||
```
|
||||
|
||||
Take some inspiration of the stripe or adyen setup as these are officially supported by the system and have been developed by the original creator.
|
||||
Take some inspiration of the stripe or payrexx setup as these are officially supported by the system and have been developed by the original creator.
|
||||
|
||||
The express.js routes it has to expose are the following:
|
||||
|
||||
@@ -36,4 +15,8 @@ It can contain any number of (not interfering) routes. Please always use the /pa
|
||||
|
||||
|
||||
## The plugin.json file
|
||||
The plugin.json file should look as follows:
|
||||
The plugin.json file should look as follows:
|
||||
|
||||
## configOption.json
|
||||
This file contains the settings that should be available in the settings page of libreevent. It should contain the following fields, as required by the settings.vue module.
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* libreevent - module.payrexx.js
|
||||
*
|
||||
* Created by Janis Hutz 08/12/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
const fs = require( 'fs' );
|
||||
const path = require( 'path' );
|
||||
const qs = require( 'qs' );
|
||||
const axios = require( 'axios' );
|
||||
const Base64 = require( 'crypto-js/enc-base64' );
|
||||
const hmacSHA256 = require( 'crypto-js/hmac-sha256' );
|
||||
const payrexxConfig = JSON.parse( fs.readFileSync( path.join( __dirname + '/../../../../config/payments.config.secret.json' ) ) )[ 'payrexx' ];
|
||||
|
||||
const baseUrl = 'https://api.payrexx.com/v1.0/';
|
||||
const instance = payrexxConfig.instance;
|
||||
const secret = payrexxConfig.APISecret;
|
||||
|
||||
exports.init = function () {
|
||||
function buildSignature ( query = '' ) {
|
||||
return Base64.stringify( hmacSHA256( query, secret ) );
|
||||
}
|
||||
|
||||
function buildBaseUrl ( path ) {
|
||||
return baseUrl + path + '?instance=' + instance;
|
||||
}
|
||||
|
||||
return {
|
||||
getGateway: function ( id ) {
|
||||
const baseUrl = buildBaseUrl( 'Gateway/' + id + '/' );
|
||||
const url = baseUrl + '&ApiSignature=' + buildSignature();
|
||||
return axios.get( url );
|
||||
},
|
||||
createGateway: function ( params ) {
|
||||
if ( !params.amount ) {
|
||||
throw new Error( 'Amount required!' );
|
||||
}
|
||||
|
||||
const defaultParams = {
|
||||
currency: 'CHF'
|
||||
};
|
||||
|
||||
let queryParams = Object.assign( {}, defaultParams, params );
|
||||
|
||||
const queryStr = qs.stringify( queryParams, { format: 'RFC1738' } );
|
||||
const signature = buildSignature( queryStr );
|
||||
|
||||
queryParams.ApiSignature = signature;
|
||||
const queryStrSigned = qs.stringify( queryParams );
|
||||
|
||||
const baseUrl = buildBaseUrl( 'Gateway/' );
|
||||
return axios.post( baseUrl, queryStrSigned );
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* libreevent - payrexxRoutes.js
|
||||
*
|
||||
* Created by Janis Hutz 08/12/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
const fs = require( 'fs' );
|
||||
const path = require( 'path' );
|
||||
const db = require( '../../../db/db.js' );
|
||||
const payrexxConfig = JSON.parse( fs.readFileSync( path.join( __dirname + '/../../../../config/payments.config.secret.json' ) ) )[ 'payrexx' ];
|
||||
const bodyParser = require( 'body-parser' );
|
||||
const ticket = require( '../../../tickets/ticketGenerator.js' );
|
||||
const payrexxModule = require( './module.payrexx.js' );
|
||||
const payrexx = payrexxModule.init();
|
||||
const TicketGenerator = new ticket();
|
||||
|
||||
|
||||
let sessionReference = {};
|
||||
let waitingClients = {};
|
||||
let pendingPayments = {};
|
||||
let paymentOk = {};
|
||||
|
||||
module.exports = ( app, settings ) => {
|
||||
app.post( '/payments/prepare', bodyParser.json(), ( req, res ) => {
|
||||
if ( req.session.loggedInUser ) {
|
||||
let purchase = {
|
||||
'successRedirectUrl': settings.yourDomain + '/payments/success',
|
||||
'cancelRedirectUrl': settings.yourDomain + '/payments/canceled',
|
||||
'failedRedirectUrl': settings.yourDomain + '/payments/failed',
|
||||
'currency': settings.currency,
|
||||
'basket': [],
|
||||
'pm': payrexxConfig.paymentMethods,
|
||||
'amount': 0,
|
||||
};
|
||||
|
||||
db.getDataSimple( 'temp', 'user_id', req.session.id ).then( dat => {
|
||||
if ( dat[ 0 ] ) {
|
||||
db.getJSONData( 'events' ).then( events => {
|
||||
let data = JSON.parse( dat[ 0 ].data );
|
||||
( async () => {
|
||||
for ( let event in data ) {
|
||||
for ( let item in data[ event ] ) {
|
||||
purchase[ 'basket' ].push( {
|
||||
'name': data[ event ][ item ].name,
|
||||
'quantity': data[ event ][ item ].count ?? 1,
|
||||
'amount': Math.round( parseFloat( events[ event ][ 'categories' ][ data[ event ][ item ].category ].price[ data[ event ][ item ][ 'ticketOption' ] ] ) * 100 ),
|
||||
} );
|
||||
purchase[ 'amount' ] += Math.round( parseFloat( events[ event ][ 'categories' ][ data[ event ][ item ].category ].price[ data[ event ][ item ][ 'ticketOption' ] ] ) * 100 ) * ( data[ event ][ item ].count ?? 1 );
|
||||
}
|
||||
}
|
||||
const response = await payrexx.createGateway( purchase );
|
||||
if ( response.status === 200 ) {
|
||||
const session = response.data.data[ 0 ];
|
||||
sessionReference[ session.id ] = { 'tok': req.session.id, 'email': req.session.username };
|
||||
pendingPayments[ req.session.id ] = true;
|
||||
res.send( session.link );
|
||||
} else {
|
||||
res.status( 500 ).send( 'ERR_PAYMENT' );
|
||||
}
|
||||
} )();
|
||||
} );
|
||||
} else {
|
||||
res.status( 400 ).send( 'ERR_UID_NOT_FOUND' );
|
||||
}
|
||||
} ).catch( error => {
|
||||
console.error( '[ STRIPE ] DB ERROR: ' + error );
|
||||
res.status( 500 ).send( 'ERR_DB' );
|
||||
} );
|
||||
} else {
|
||||
res.status( 403 ).send( 'ERR_UNAUTHORIZED' );
|
||||
}
|
||||
} );
|
||||
|
||||
app.get( '/payments/status', ( request, response ) => {
|
||||
response.writeHead( 200, {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive',
|
||||
} );
|
||||
response.status( 200 );
|
||||
response.flushHeaders();
|
||||
response.write( 'data: connected\n\n' );
|
||||
waitingClients[ request.session.id ] = response;
|
||||
const ping = setInterval( () => {
|
||||
if ( !pendingPayments[ request.session.id ] ) {
|
||||
const stat = TicketGenerator.getGenerationStatus( request.session.id );
|
||||
if ( stat === 'done' ) {
|
||||
clearInterval( ping );
|
||||
setTimeout( () => {
|
||||
response.write( 'data: ready\n\n' );
|
||||
response.end();
|
||||
delete waitingClients[ request.session.id ];
|
||||
}, 2000 );
|
||||
} else if ( stat === 'noTicket' ) {
|
||||
clearInterval( ping );
|
||||
response.write( 'data: noData\n\n' );
|
||||
response.end();
|
||||
delete waitingClients[ request.session.id ];
|
||||
}
|
||||
}
|
||||
}, 2000 );
|
||||
} );
|
||||
|
||||
app.get( '/user/2fa/ping', ( request, response ) => {
|
||||
if ( paymentOk[ request.session.id ] === 'ok' ) {
|
||||
delete paymentOk[ request.session.id ];
|
||||
response.send( { 'status': 'paymentOk' } );
|
||||
} else {
|
||||
if ( !pendingPayments[ request.session.id ] ) {
|
||||
const stat = TicketGenerator.getGenerationStatus( request.session.id );
|
||||
if ( stat === 'done' ) {
|
||||
response.send( { 'status': 'ticketOk' } );
|
||||
} else if ( stat === 'noTicket' ) {
|
||||
response.send( { 'status': 'noTicket' } );
|
||||
} else {
|
||||
response.send( '' );
|
||||
}
|
||||
} else {
|
||||
response.send( '' );
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
app.post( '/payments/webhook', bodyParser.raw( { type: 'application/json' } ), async ( req, res ) => {
|
||||
console.error( req.body );
|
||||
const response = await payrexx.getGateway( req.body.id );
|
||||
|
||||
if ( response.status === 200 ) {
|
||||
const gateway = response.data.data[ 0 ];
|
||||
|
||||
res.status( 200 ).end();
|
||||
if ( gateway.status === 'confirmed' ) {
|
||||
setTimeout( () => {
|
||||
if ( waitingClients[ sessionReference[ response.data.data[ 0 ].id ][ 'tok' ] ] ) {
|
||||
waitingClients[ sessionReference[ response.data.data[ 0 ].id ][ 'tok' ] ].write( 'data: paymentOk\n\n' );
|
||||
}
|
||||
}, 1000 );
|
||||
db.getDataSimple( 'temp', 'user_id', sessionReference[ response.data.data[ 0 ].id ][ 'tok' ] ).then( dat => {
|
||||
db.getDataSimple( 'users', 'email', sessionReference[ response.data.data[ 0 ].id ][ 'email' ] ).then( user => {
|
||||
if ( user[ 0 ] ) {
|
||||
const tickets = JSON.parse( dat[ 0 ].data );
|
||||
db.writeDataSimple( 'orders', 'account_id', user[ 0 ].account_id, { 'account_id': user[ 0 ].account_id, 'tickets': dat[ 0 ].data, 'order_name': sessionReference[ response.data.data[ 0 ].id ][ 'tok' ] } ).then( () => {
|
||||
console.log( sessionReference[ response.data.data[ 0 ].id ][ 'tok' ] );
|
||||
TicketGenerator.generateTickets( sessionReference[ response.data.data[ 0 ].id ] );
|
||||
db.getJSONData( 'booked' ).then( ret => {
|
||||
let booked = ret ?? {};
|
||||
for ( let event in tickets ) {
|
||||
if ( !booked[ String( event ) ] ) {
|
||||
booked[ String( event ) ] = {};
|
||||
}
|
||||
for ( let tik in tickets[ event ] ) {
|
||||
booked[ event ][ tik ] = tickets[ event ][ tik ];
|
||||
}
|
||||
}
|
||||
db.writeJSONData( 'booked', booked ).then( () => {
|
||||
delete pendingPayments[ sessionReference[ response.data.data[ 0 ].id ][ 'tok' ] ];
|
||||
} );
|
||||
db.deleteDataSimple( 'temp', 'user_id', sessionReference[ response.data.data[ 0 ].id ][ 'tok' ] ).catch( error => {
|
||||
console.error( '[ STRIPE ] ERROR whilst deleting data from DB: ' + error );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
} else {
|
||||
console.log( sessionReference[ response.data.data[ 0 ].id ][ 'email' ] );
|
||||
console.error( 'user not found' );
|
||||
}
|
||||
} );
|
||||
} ).catch( err => {
|
||||
console.error( err );
|
||||
} );
|
||||
}
|
||||
}
|
||||
} );
|
||||
};
|
||||
@@ -10,21 +10,19 @@
|
||||
const fs = require( 'fs' );
|
||||
const path = require( 'path' );
|
||||
const db = require( '../../../db/db.js' );
|
||||
const stripConfig = JSON.parse( fs.readFileSync( path.join( __dirname + '/../../../../config/payments.config.secret.json' ) ) )[ 'stripe' ];
|
||||
const stripe = require( 'stripe' )( stripConfig[ 'APIKey' ] );
|
||||
const stripeConfig = JSON.parse( fs.readFileSync( path.join( __dirname + '/../../../../config/payments.config.secret.json' ) ) )[ 'stripe' ];
|
||||
const stripe = require( 'stripe' )( stripeConfig[ 'APIKey' ] );
|
||||
const bodyParser = require( 'body-parser' );
|
||||
const ticket = require( '../../../tickets/ticketGenerator.js' );
|
||||
const TicketGenerator = new ticket();
|
||||
|
||||
const endpointSecret = stripConfig[ 'endpointSecret' ];
|
||||
const endpointSecret = stripeConfig[ 'endpointSecret' ];
|
||||
|
||||
let sessionReference = {};
|
||||
let waitingClients = {};
|
||||
let pendingPayments = {};
|
||||
let paymentOk = {};
|
||||
|
||||
// TODO: Remove all selected tickets if timestamp more than user defined amount ago
|
||||
|
||||
module.exports = ( app, settings ) => {
|
||||
app.post( '/payments/prepare', bodyParser.json(), ( req, res ) => {
|
||||
if ( req.session.loggedInUser ) {
|
||||
|
||||
Reference in New Issue
Block a user