Skip to content

Commit

Permalink
Merge pull request #66 from Moonpig/feature/lambdarise-extension-module
Browse files Browse the repository at this point in the history
Change all interfaceId fields to use custom.fields.merchantReference instead
  • Loading branch information
LEQADA committed Jun 13, 2019
2 parents 98ce6ff + c5657bc commit 69e269a
Show file tree
Hide file tree
Showing 23 changed files with 88 additions and 35 deletions.
3 changes: 2 additions & 1 deletion extension/docs/IntegrationGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ or by asynchronous process like [commercetools-payment-to-order-processor job](h
### Validate payment
There must be at least one CTP payment object of type Adyen
(`Payment.paymentMethodInfo.paymentInterface = ctp-adyen-integration`)
AND this CTP payment must have `Payment.interfaceId`.
AND this CTP payment must have `Payment.custom.fields.merchantReference`.
The combination of `Payment.custom.fields.merchantReference` and `Payment.paymentMethodInfo.paymentInterface` must be unique across the project. This field must not be changed once set.

### Validate payment transaction
Cart's payment counts as successful if there is at least one payment object
Expand Down
11 changes: 11 additions & 0 deletions extension/resources/payment-custom-types.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@
"payment"
],
"fieldDefinitions": [
{
"type": {
"name": "String"
},
"name": "merchantReference",
"label": {
"en": "merchantReference"
},
"required": true,
"inputHint": "SingleLine"
},
{
"type": {
"name": "String"
Expand Down
8 changes: 4 additions & 4 deletions extension/src/api/payment/payment.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ async function processRequest (request, response) {
if (adyenValidator.hasErrors())
// if it's not adyen payment, ignore the payment
return httpUtils.sendResponse({ response })
const interfaceIdValidator = validatorBuilder
.validateInterfaceIdField()
if (interfaceIdValidator.hasErrors())
const merchantReferenceValidator = validatorBuilder
.validateMerchantReferenceField()
if (merchantReferenceValidator.hasErrors())
return httpUtils.sendResponse({
response,
statusCode: 400,
data: interfaceIdValidator.buildCtpErrorResponse()
data: merchantReferenceValidator.buildCtpErrorResponse()
})
const paymentMethodValidator = validatorBuilder.validatePaymentMethod()
if (paymentMethodValidator.hasErrors())
Expand Down
2 changes: 1 addition & 1 deletion extension/src/paymentHandler/cancel-or-refund.handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async function _cancelOrRefundPayment (paymentObject) {
const body = {
merchantAccount: config.adyen.merchantAccount,
originalReference: transaction.interactionId,
reference: paymentObject.interfaceId
reference: paymentObject.custom.fields.merchantReference
}

const request = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ async function _makePayment (paymentObject) {
currency: transaction.amount.currencyCode,
value: transaction.amount.centAmount
},
reference: paymentObject.interfaceId,
reference: paymentObject.custom.fields.merchantReference,
paymentMethod: {
type: 'scheme',
encryptedCardNumber: paymentObject.custom.fields.encryptedCardNumber,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ async function _callAdyen (paymentObject) {
currency: transaction.amount.currencyCode,
value: transaction.amount.centAmount
},
reference: paymentObject.interfaceId,
reference: paymentObject.custom.fields.merchantReference,
paymentMethod: {
type: paymentMethodType
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ async function _callAdyen (paymentObject) {
currency: transaction.amount.currencyCode,
value: transaction.amount.centAmount
},
reference: paymentObject.interfaceId,
reference: paymentObject.custom.fields.merchantReference,
paymentMethod: {
type: 'paypal'
},
Expand Down
2 changes: 1 addition & 1 deletion extension/src/validator/error-messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module.exports = {
MISSING_EXPIRY_YEAR: 'Set custom.fields.encryptedExpiryYear',
MISSING_SECURITY_CODE: 'Set custom.fields.encryptedSecurityCode',
MISSING_RETURN_URL: 'Set custom.fields.returnUrl',
MISSING_INTERFACE_ID: 'Set interfaceId',
MISSING_MERCHANT_REFERENCE: 'Set custom merchantReference',
MISSING_PAYLOAD: 'Set custom.fields.payload',
MISSING_PAYMENT_DATA: 'Set custom.fields.paymentData',
MISSING_PARES: 'Set custom.fields.PaRes',
Expand Down
8 changes: 4 additions & 4 deletions extension/src/validator/validator-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ function withPayment (paymentObject) {
errors.hasReturnUrl = errorMessages.MISSING_RETURN_URL
return this
},
validateInterfaceIdField () {
const hasInterfaceId = !_.isEmpty(paymentObject.interfaceId)
if (!hasInterfaceId)
errors.hasInterfaceId = errorMessages.MISSING_INTERFACE_ID
validateMerchantReferenceField () {
const hasMerchantReference = !_.isEmpty(paymentObject.custom.fields.merchantReference)
if (!hasMerchantReference)
errors.hasMerchantReference = errorMessages.MISSING_MERCHANT_REFERENCE
return this
},
validatePayloadField () {
Expand Down
2 changes: 1 addition & 1 deletion extension/test/fixtures/ctp-payment.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"createdBy": {
"clientId": "GfjD1YgZgpe0K6wEdUEpwTmx"
},
"interfaceId": "paymentReferenceId",
"amountPlanned": {
"type": "centPrecision",
"currencyCode": "EUR",
Expand All @@ -27,6 +26,7 @@
"id": "3bb94fa2-6254-4a31-83e8-a2a882c15173"
},
"fields": {
"merchantReference": "paymentReferenceId",
"redirectUrl": "redirectUrl",
"redirectMethod": "redirectMethod",
"returnUrl": "returnUrl",
Expand Down
2 changes: 1 addition & 1 deletion extension/test/fixtures/payment-credit-card-3d.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"interfaceId":"paymentReferenceId",
"amountPlanned": {
"type": "centPrecision",
"currencyCode": "EUR",
Expand All @@ -16,6 +15,7 @@
"key": "ctp-adyen-integration-payment-custom-type"
},
"fields": {
"merchantReference": "paymentReferenceId",
"countryCode": "DE",
"encryptedCardNumber":"${encryptedCardNumber}",
"encryptedExpiryMonth":"${encryptedExpiryMonth}",
Expand Down
2 changes: 1 addition & 1 deletion extension/test/fixtures/payment-credit-card.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"interfaceId":"paymentReferenceId",
"amountPlanned": {
"type": "centPrecision",
"currencyCode": "EUR",
Expand All @@ -16,6 +15,7 @@
"key": "ctp-adyen-integration-payment-custom-type"
},
"fields": {
"merchantReference": "paymentReferenceId",
"countryCode": "DE",
"encryptedCardNumber":"${encryptedCardNumber}",
"encryptedExpiryMonth":"${encryptedExpiryMonth}",
Expand Down
2 changes: 1 addition & 1 deletion extension/test/fixtures/payment-kcp.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"interfaceId":"paymentReferenceId",
"amountPlanned": {
"type": "centPrecision",
"currencyCode": "EUR",
Expand All @@ -16,6 +15,7 @@
"key": "ctp-adyen-integration-payment-custom-type"
},
"fields": {
"merchantReference": "paymentReferenceId",
"returnUrl":"https://your-company.com/checkout/"
}
},
Expand Down
2 changes: 1 addition & 1 deletion extension/test/fixtures/payment-no-method.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"interfaceId": "pspReference",
"amountPlanned": {
"type": "centPrecision",
"currencyCode": "EUR",
Expand All @@ -15,6 +14,7 @@
"key": "ctp-adyen-integration-payment-custom-type"
},
"fields": {
"merchantReference": "paymentReferenceId",
"countryCode": "DE"
}
},
Expand Down
2 changes: 1 addition & 1 deletion extension/test/fixtures/payment-paypal.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"interfaceId":"paymentReferenceId",
"amountPlanned": {
"type": "centPrecision",
"currencyCode": "EUR",
Expand All @@ -16,6 +15,7 @@
"key": "ctp-adyen-integration-payment-custom-type"
},
"fields": {
"merchantReference":"paymentReferenceId",
"returnUrl":"https://your-company.com/checkout/"
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('credit card payment', () => {

const adyenRequestBody = JSON.parse(adyenRequest.body)
expect(adyenRequestBody.merchantAccount).to.be.equal(process.env.ADYEN_MERCHANT_ACCOUNT)
expect(adyenRequestBody.reference).to.be.equal(paymentTemplate.interfaceId)
expect(adyenRequestBody.reference).to.be.equal(paymentTemplate.custom.fields.merchantReference)
expect(adyenRequestBody.returnUrl).to.be.equal(paymentTemplate.custom.fields.returnUrl)
expect(adyenRequestBody.amount.currency).to.be.equal(paymentTemplate.transactions[0].amount.currencyCode)
expect(adyenRequestBody.amount.value).to.be.equal(paymentTemplate.transactions[0].amount.centAmount)
Expand Down Expand Up @@ -75,7 +75,7 @@ describe('credit card payment', () => {

const adyenRequestBody = JSON.parse(adyenRequest.body)
expect(adyenRequestBody.merchantAccount).to.be.equal(process.env.ADYEN_MERCHANT_ACCOUNT)
expect(adyenRequestBody.reference).to.be.equal(paymentTemplate.interfaceId)
expect(adyenRequestBody.reference).to.be.equal(paymentTemplate.custom.fields.merchantReference)
expect(adyenRequestBody.returnUrl).to.be.equal(`${process.env.API_EXTENSION_BASE_URL}/test-return-url`)
expect(adyenRequestBody.amount.currency).to.be.equal(paymentTemplate.transactions[0].amount.currencyCode)
expect(adyenRequestBody.amount.value).to.be.equal(paymentTemplate.transactions[0].amount.centAmount)
Expand Down
18 changes: 9 additions & 9 deletions extension/test/unit/payment.controller.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ describe('Payment controller', () => {
await paymentController.processRequest(mockRequest)
})

it('on missing interface id should throw error', async () => {
it('on missing merchant reference should throw error', async () => {
const ctpPaymentClone = _.cloneDeep(ctpPayment)
ctpPaymentClone.interfaceId = ''
ctpPaymentClone.custom.fields.merchantReference = ''

utilsStub.collectRequestData = () => JSON.stringify({ resource: { obj: ctpPaymentClone } })
utilsStub.sendResponse = ({ statusCode, data }) => {
expect(statusCode).to.equal(400)
expect(data).to.deep.equal({
errors: [{
code: 'InvalidField',
message: errorMessages.MISSING_INTERFACE_ID
message: errorMessages.MISSING_MERCHANT_REFERENCE
}]
})
}
Expand All @@ -46,7 +46,7 @@ describe('Payment controller', () => {

it('on wrong payment method should throw error', async () => {
const ctpPaymentClone = _.cloneDeep(ctpPayment)
ctpPaymentClone.custom.fields = {}
ctpPaymentClone.custom.fields = {"merchantReference": "paymentReferenceId"}
ctpPaymentClone.paymentMethodInfo.method = 'wrong method'

utilsStub.collectRequestData = () => JSON.stringify({ resource: { obj: ctpPaymentClone } })
Expand All @@ -65,7 +65,7 @@ describe('Payment controller', () => {

it('on missing params for make paypal payment should throw error', async () => {
const ctpPaymentClone = _.cloneDeep(ctpPayment)
ctpPaymentClone.custom.fields = {}
ctpPaymentClone.custom.fields = {"merchantReference": "paymentReferenceId"}
ctpPaymentClone.paymentMethodInfo.method = 'paypal'
ctpPaymentClone.transactions[0].state = 'Initial'

Expand All @@ -85,7 +85,7 @@ describe('Payment controller', () => {

it('on missing params for complete paypal payment should throw error', async () => {
const ctpPaymentClone = _.cloneDeep(ctpPayment)
ctpPaymentClone.custom.fields = {}
ctpPaymentClone.custom.fields = {"merchantReference": "paymentReferenceId"}
ctpPaymentClone.paymentMethodInfo.method = 'paypal'
ctpPaymentClone.transactions[0].state = 'Pending'

Expand All @@ -100,7 +100,7 @@ describe('Payment controller', () => {

it('on missing params for make credit card payment should throw error', async () => {
const ctpPaymentClone = _.cloneDeep(ctpPayment)
ctpPaymentClone.custom.fields = {}
ctpPaymentClone.custom.fields = {"merchantReference": "paymentReferenceId"}
ctpPaymentClone.paymentMethodInfo.method = 'creditCard'
ctpPaymentClone.transactions[0].state = 'Initial'

Expand Down Expand Up @@ -137,7 +137,7 @@ describe('Payment controller', () => {

it('on missing params for make 3ds payment should throw error', async () => {
const ctpPaymentClone = _.cloneDeep(ctpPayment)
ctpPaymentClone.custom.fields = {}
ctpPaymentClone.custom.fields = {"merchantReference": "paymentReferenceId"}
ctpPaymentClone.paymentMethodInfo.method = 'creditCard_3d'
ctpPaymentClone.transactions[0].state = 'Initial'

Expand Down Expand Up @@ -174,7 +174,7 @@ describe('Payment controller', () => {

it('on missing params for complete credit card payment should throw error', async () => {
const ctpPaymentClone = _.cloneDeep(ctpPayment)
ctpPaymentClone.custom.fields = {}
ctpPaymentClone.custom.fields = {"merchantReference": "paymentReferenceId"}
ctpPaymentClone.paymentMethodInfo.method = 'creditCard_3d'
ctpPaymentClone.transactions[0].state = 'Pending'

Expand Down
4 changes: 2 additions & 2 deletions notification/src/handler/notification/notification.handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async function updatePaymentWithRepeater (payment, notification, ctpClient) {
try {
/* eslint-disable-next-line no-await-in-loop */
await ctpClient.update(ctpClient.builder.payments, currentPayment.id, currentVersion, updateActions)
logger.debug(`Payment with interfaceId ${currentPayment.interfaceId}`
logger.debug(`Payment with merchantReference ${currentPayment.custom.fields.merchantReference}`
+ 'was successfully updated')
break
} catch (err) {
Expand Down Expand Up @@ -146,7 +146,7 @@ function getAddTransactionUpdateAction (type, state, amount, currency) {

async function getPaymentByMerchantReference (merchantReference, ctpClient) {
try {
const result = await ctpClient.fetch(ctpClient.builder.payments.where(`interfaceId="${merchantReference}"`))
const result = await ctpClient.fetch(ctpClient.builder.payments.where(`custom(fields(merchantReference="${merchantReference}"))`))
return _.get(result, 'body.results[0]', null)
} catch (err) {
throw Error(`Failed to fetch a payment with merchantReference: ${merchantReference}. `
Expand Down
21 changes: 21 additions & 0 deletions notification/test/integration/init/ensure-payment-custom-type.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const paymentCustomType = require('../../resources/payment-custom-types.json')

const utils = require('../../../src/utils/logger')

const logger = utils.getLogger()

async function ensurePaymentCustomType (ctpClient) {
try {
const { body } = await ctpClient.fetch(ctpClient.builder.types.where(`key="${paymentCustomType.key}"`))
if (body.results.length === 0) {
await ctpClient.create(ctpClient.builder.types, paymentCustomType)
logger.info('Successfully created payment custom type')
}
} catch (e) {
logger.error(e, 'Error when creating payment custom type, skipping...')
}
}

module.exports = {
ensurePaymentCustomType
}
2 changes: 2 additions & 0 deletions notification/test/integration/init/init-resources.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
const {
ensureInterfaceInteractionCustomType
} = require('../../../src/config/init/ensure-interface-interaction-custom-type')
const { ensurePaymentCustomType } = require('./ensure-payment-custom-type')
const { ensurePayment } = require('./ensure-payment')

async function ensureResources (ctpClient) {
await ensureInterfaceInteractionCustomType(ctpClient)
await ensurePaymentCustomType(ctpClient)
await ensurePayment(ctpClient)
}

Expand Down
2 changes: 1 addition & 1 deletion notification/test/resources/payment-credit-card.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"id": "123212321",
"version": "2",
"interfaceId":"paymentReferenceId",
"amountPlanned": {
"type": "centPrecision",
"currencyCode": "EUR",
Expand All @@ -19,6 +18,7 @@
},
"fields": {
"countryCode": "DE",
"merchantReference":"paymentReferenceId",
"encryptedCardNumber":"${encryptedCardNumber}",
"encryptedExpiryMonth":"${encryptedExpiryMonth}",
"encryptedExpiryYear":"${encryptedExpiryYear}",
Expand Down
11 changes: 11 additions & 0 deletions notification/test/resources/payment-custom-types.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@
"payment"
],
"fieldDefinitions": [
{
"type": {
"name": "String"
},
"name": "merchantReference",
"label": {
"en": "merchantReference"
},
"required": true,
"inputHint": "SingleLine"
},
{
"type": {
"name": "String"
Expand Down
9 changes: 8 additions & 1 deletion notification/test/resources/payment-draft.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
{
"key": "test-payment",
"interfaceId": "8313842560770001",
"amountPlanned": {
"type": "centPrecision",
"currencyCode": "EUR",
"centAmount": 795,
"fractionDigits": 2
},
"custom": {
"type": {
"key": "ctp-adyen-integration-payment-custom-type"
},
"fields": {
"merchantReference": "8313842560770001"
}
},
"transactions": [
{
"type": "Authorization",
Expand Down

0 comments on commit 69e269a

Please sign in to comment.