Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ You can see the API the gateway intends to fulfill by looking at the [BaseGatewa

**Note:** All builds are run daily thanks to [Travis CI cron jobs](https://docs.travis-ci.com/user/cron-jobs/).

- Omise
- Stripe
- Braintree
- PayPal
- WorldPay
- Beanstream
- Payeezy

[![Build Status](https://travis-ci.org/continuous-software/42-cent-braintree.svg?branch=master)](https://travis-ci.org/continuous-software/42-cent-braintree) [Braintree](https://github.com/continuous-software/42-cent-braintree)
[![Build Status](https://travis-ci.org/continuous-software/42-cent-omise.svg?branch=master)](https://travis-ci.org/continuous-software/42-cent-omise) [Omise](https://github.com/continuous-software/42-cent-omise)
[![Build Status](https://travis-ci.org/continuous-software/42-cent-stripe.svg?branch=master)](https://travis-ci.org/continuous-software/42-cent-stripe) [Stripe](https://github.com/continuous-software/42-cent-stripe)
Expand All @@ -52,3 +60,22 @@ Feel free to go and fix things if you can.
[![Build Status](https://travis-ci.org/continuous-software/node-payflow.svg?branch=master)](https://travis-ci.org/continuous-software/node-payflow) [Payflow](https://github.com/continuous-software/node-payflow)
[![Build Status](https://travis-ci.org/continuous-software/node-rocketgate.svg?branch=master)](https://travis-ci.org/continuous-software/node-rocketgate) [RocketGate](https://github.com/continuous-software/node-rocketgate)
[![Build Status](https://travis-ci.org/continuous-software/node-virtualmerchant.svg?branch=master)](https://travis-ci.org/continuous-software/node-virtualmerchant) [VirtualMerchant](https://github.com/continuous-software/node-virtualmerchant)

## Gateway Specific Configuration

### Payeezy

```javascript
var client = Gateways.use('Payeezy', {
apiKey: 'your-api-key',
apiSecret: 'your-api-secret',
merchantToken: 'your-merchant-token',
environment: 'sandbox' // or 'production'
});
```

Required configuration:
- `apiKey`: Your Payeezy API key
- `apiSecret`: Your Payeezy API secret
- `merchantToken`: Your Payeezy merchant token
- `environment`: Either 'sandbox' or 'production' (default: 'sandbox')
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var PayPal = require('42-cent-paypal').factory;
var WorldPay = require('42-cent-worldpay').factory;
var Beanstream = require('42-cent-beanstream').factory;
var Moneris = require('42-cent-moneris');
var Payeezy = require('./lib/PayeezyGateway').factory;

// Deprecated:
// var AuthorizeNet = require('authorize-net');
Expand All @@ -22,6 +23,7 @@ var supportedGateway = {
"PayPal": PayPal,
"WorldPay": WorldPay,
"Beanstream": Beanstream,
"Payeezy": Payeezy,
// "Authorize.Net": AuthorizeNet,
// "PayFlow": PayFlow,
// "RocketGate": RocketGate,
Expand Down
137 changes: 137 additions & 0 deletions lib/PayeezyGateway.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
'use strict';

const BaseGateway = require('42-cent-base').BaseGateway;
const CreditCard = require('42-cent-model').CreditCard;
const Prospect = require('42-cent-model').Prospect;
const Promise = require('bluebird');
const _ = require('lodash');
const crypto = require('crypto');

class PayeezyGateway extends BaseGateway {
constructor(options) {
super();
this.apiKey = options.apiKey;
this.apiSecret = options.apiSecret;
this.merchantToken = options.merchantToken;
this.environment = options.environment || 'sandbox';
this.baseUrl = this.environment === 'sandbox'
? 'https://api-cert.payeezy.com/v1'
: 'https://api.payeezy.com/v1';
}

generateHmac(payload, timestamp) {
const message = this.apiKey + timestamp + this.merchantToken + JSON.stringify(payload);
return crypto
.createHmac('sha256', this.apiSecret)
.update(message)
.digest('hex');
}

async submitTransaction(transaction) {
const timestamp = new Date().getTime();
const hmac = this.generateHmac(transaction, timestamp);

const headers = {
'Content-Type': 'application/json',
'apikey': this.apiKey,
'token': this.merchantToken,
'timestamp': timestamp,
'hmac': hmac
};

try {
const response = await fetch(`${this.baseUrl}/transactions`, {
method: 'POST',
headers: headers,
body: JSON.stringify(transaction)
});

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.json();
return this.createTransactionResponse(data);
} catch (error) {
throw new Error(`Failed to process transaction: ${error.message}`);
}
}

createTransactionResponse(response) {
return {
transactionId: response.transaction_id,
_original: response,
authCode: response.authorization_num,
status: response.transaction_status
};
}

submitTransaction(order, creditCard, prospect, other) {
const payload = {
merchant_ref: order.orderId || Date.now().toString(),
transaction_type: 'purchase',
method: 'credit_card',
amount: order.amount,
currency_code: order.currency || 'USD',
credit_card: {
type: this.getCardType(creditCard.cardNumber),
cardholder_name: creditCard.cardHolder,
card_number: creditCard.cardNumber,
exp_date: creditCard.expirationMonth.toString().padStart(2, '0') + creditCard.expirationYear.toString().slice(-2),
cvv: creditCard.cvv
}
};

if (prospect) {
payload.billing_address = {
name: prospect.firstName + ' ' + prospect.lastName,
street: prospect.address1,
city: prospect.city,
state_province: prospect.state,
zip_postal_code: prospect.zip,
country: prospect.country || 'US'
};
}

return this.submitTransaction(payload);
}

getCardType(number) {
// Basic card type detection
if (/^4/.test(number)) return 'visa';
if (/^5[1-5]/.test(number)) return 'mastercard';
if (/^3[47]/.test(number)) return 'amex';
if (/^6(?:011|5)/.test(number)) return 'discover';
return 'unknown';
}

refundTransaction(transactionId, options) {
const payload = {
merchant_ref: options.orderId || Date.now().toString(),
transaction_type: 'refund',
method: 'credit_card',
amount: options.amount,
currency_code: options.currency || 'USD',
transaction_tag: options.transactionTag,
transaction_id: transactionId
};

return this.submitTransaction(payload);
}

voidTransaction(transactionId, options) {
const payload = {
merchant_ref: options.orderId || Date.now().toString(),
transaction_type: 'void',
method: 'credit_card',
transaction_tag: options.transactionTag,
transaction_id: transactionId
};

return this.submitTransaction(payload);
}
}

exports.factory = function (options) {
return new PayeezyGateway(options);
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"nmi": "^1.0.3",
"payflow": "^1.0.0",
"rocketgate": "^1.0.0",
"virtualmerchant": "^1.0.0"
"virtualmerchant": "^1.0.0",
"42-cent-payeezy": "^1.0.0"
},
"devDependencies": {
"mocha": "^1.21.4"
Expand Down