Skip to content

Commit

Permalink
#468 replace originKey with clientKey (#469)
Browse files Browse the repository at this point in the history
  • Loading branch information
lojzatran authored Nov 4, 2020
2 parents 0bc4f3d + 0420bcc commit 6613535
Show file tree
Hide file tree
Showing 32 changed files with 144 additions and 375 deletions.
18 changes: 18 additions & 0 deletions extension/docs/DevelopmentGuide.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [Development Guide](#development-guide)
- [Contents](#contents)
- [Prerequisites](#prerequisites)
- [Development](#development)
- [E2E tests](#e2e-tests)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

# Development Guide

## Contents
Expand Down Expand Up @@ -26,3 +38,9 @@ While developing project you can use some predefined commands for running tests,
- Execute `npm run lint` to show lint errors in the code.

> You need to set [environment variables](./DeploymentGuide.md#environment-variables) to be able to run integration and e2e tests.
Additionally, there could be more environmental variables needed for tests. See the next sections of this documentation.

#### E2E tests
Following additional environment variables must be provided in order to run the E2E tests.
| Name | Content | Required | Default value |
|`ADYEN_CLIENT_KEY` | Client-side key that is required to render a Component. See [Adyen documentation](https://docs.adyen.com/development-resources/client-side-authentication#get-your-client-key). | YES | |
58 changes: 4 additions & 54 deletions extension/docs/WebComponentsIntegrationGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,17 @@ Terms used in this guide:

The following diagram shows checkout integration flow based on [Adyen Web Components](https://docs.adyen.com/checkout/components-web).

![Flow](https://user-images.githubusercontent.com/3469524/86238652-2c427080-bb9e-11ea-83cf-246bbc3a23f3.png)
![Flow](https://user-images.githubusercontent.com/803826/98081637-c467a380-1e77-11eb-93ed-003f7e68b59a.png)

## How it works

- [Step 1](#step-1-commercetools-checkout-validations) : Execute required checkout validations.
- [Step 2](#step-2-get-available-payment-methods): Set `getPaymentMethodsRequest` custom field to commercetools payment to get the list of payment methods available for the checkout.
- [Step 3](#step-3-add-components-to-your-payments-form): Set `getOriginKeysRequest` custom field to commercetools payment to get origin key and add the specific payment method Component to your checkout payments form.
- [Step 3](#step-3-add-components-to-your-payments-form): Add Adyen Web Component to your checkout payments form.
- [Step 4](#step-4-make-a-payment): Submit a payment request by setting `makePaymentRequest` payment custom field with the payment data returned by the Adyen web component.
- [Step 5](#step-5-submit-additional-payment-details): Set `submitAdditionalPaymentDetailsRequest ` custom field to commercetools payment to submit additional payment details.
- [Step 6](#step-6-capture-payment-required-for-klarna): Add an optional `Charge` transaction to commercetools payment in order to manually capture the payment.

> **Note** for Step 2 and Step 3: For a better performance `getOriginKeysRequest` can be supplied together with `getPaymentMethodsRequest` and the responses could be cached by the merchant server.
## Before you begin
In order to make the extension module up and running, follow our [deployment guide](./DeploymentGuide.md). For the sake of readability,
the field [`applicationInfo`](https://docs.adyen.com/development-resources/building-adyen-solutions#building-a-plugin) is ommitted from all the examples in this document.
Expand Down Expand Up @@ -168,57 +166,9 @@ Next, use the Adyen `Component` to render the payment method, and collect the re

If you haven't created the payment forms already in your frontend, follow the official Adyen [Web Components integration guide](https://docs.adyen.com/checkout/components-web#step-2-add-components).

An `origin key` is a client-side key that is used to validate Adyen's JavaScript component library. It is required to render a Component.

In order to get the origin key [update commercetools payment](https://docs.commercetools.com/http-api-projects-payments#update-payment) with `getOriginKeysRequest` custom field.
Note: if you want to get both origin keys and payment methods at once, you can set both `getOriginKeysRequest` and `getPaymentMethodsRequest` to the commercetools payment object within a single update request or on payment creation.

An [update action](https://docs.commercetools.com/http-api-projects-payments#set-customfield) to set `getOriginKeysRequest` custom field.
> Refer Adyen's [/originKeys](https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v52/post/originKeys) request to check all possible request payload parameters.
```
{
"version": "PAYMENT_VERSION",
"actions": [
{
"action": "setCustomField",
"name": "getOriginKeysRequest",
"value": "{\"originDomains\":[\"https://www.your-company1.com\",\"https://www.your-company2.com\"]}"
}
]
}
```

The response contains a list of origin keys for all requested domains. For each list item, the key is the domain, and the value is its associated origin key. For more info see also [origin keys](https://docs.adyen.com/user-management/how-to-get-an-origin-key)

``` json
{
"originKeys":{
"https://www.your-company1.com":"pub.v2.99...",
"https://www.your-company2.com":"pub.v2.99...",
}
}
```

The commercetools payment representation example:

``` json
{
"custom": {
"type": {
"typeId": "type",
"key": "ctp-adyen-integration-web-components-payment-type"
},
"fields": {
"getOriginKeysRequest": "{\"originDomains\":[\"https://www.your-company1.com\",\"https://www.your-company2.com\"]}",
"getOriginKeysResponse": "{\"originKeys\":{\"https://www.your-company1.com\":\"pub.v2.99...\",\"https://www.your-company2.com\":\"pub.v2.99...\"}}"
}
}
}
```
To be able to render an Adyen web component, a valid `clientKey` is needed. In order to get a `clientKey`, follow the official [Adyen documentation](https://docs.adyen.com/development-resources/client-side-authentication#get-your-client-key).

Pass the `origin key` to your front end. Origin key is required to render an Adyen payment method Component.

> **Note** for Step 2 and Step 3: For a better performance `getPaymentMethodsResponse` could be cached by the merchant server.
## Step 4: Make a payment

Expand Down
2 changes: 1 addition & 1 deletion extension/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "commercetools-adyen-integration",
"version": "5.0.0",
"version": "5.1.0",
"description": "Integration between Commercetools and Adyen payment service provider",
"license": "MIT",
"scripts": {
Expand Down
22 changes: 0 additions & 22 deletions extension/resources/web-components-payment-type.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,6 @@
"payment"
],
"fieldDefinitions": [
{
"name": "getOriginKeysRequest",
"label": {
"en": "getOriginKeysRequest"
},
"type": {
"name": "String"
},
"inputHint": "MultiLine",
"required": false
},
{
"name": "getOriginKeysResponse",
"label": {
"en": "getOriginKeysResponse"
},
"type": {
"name": "String"
},
"inputHint": "MultiLine",
"required": false
},
{
"name": "getPaymentMethodsRequest",
"label": {
Expand Down
3 changes: 2 additions & 1 deletion extension/src/config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ function getAdyenCredentials () {
merchantAccount: process.env.ADYEN_MERCHANT_ACCOUNT,
apiKey: process.env.ADYEN_API_KEY,
apiBaseUrl: process.env.ADYEN_API_BASE_URL || 'https://checkout-test.adyen.com/v52',
legacyApiBaseUrl: process.env.ADYEN_LEGACY_API_BASE_URL || 'https://pal-test.adyen.com/pal/servlet/Payment/v52'
legacyApiBaseUrl: process.env.ADYEN_LEGACY_API_BASE_URL || 'https://pal-test.adyen.com/pal/servlet/Payment/v52',
clientKey: process.env.ADYEN_CLIENT_KEY || ''
}
}

Expand Down
2 changes: 0 additions & 2 deletions extension/src/config/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ module.exports = {
CTP_INTERACTION_TYPE_CANCEL_OR_REFUND: 'cancelOrRefund',
CTP_INTERACTION_TYPE_GET_PAYMENT_METHODS: 'getPaymentMethods',
CTP_CUSTOM_FIELD_GET_PAYMENT_METHODS_RESPONSE: 'getPaymentMethodsResponse',
CTP_INTERACTION_TYPE_GET_ORIGIN_KEYS: 'getOriginKeys',
CTP_CUSTOM_FIELD_GET_ORIGIN_KEYS_RESPONSE: 'getOriginKeysResponse',
CTP_INTERACTION_TYPE_MAKE_PAYMENT: 'makePayment',
CTP_CUSTOM_FIELD_MAKE_PAYMENT_RESPONSE: 'makePaymentResponse',
CTP_INTERACTION_TYPE_SUBMIT_ADDITIONAL_PAYMENT_DETAILS: 'submitAdditionalPaymentDetails',
Expand Down
18 changes: 0 additions & 18 deletions extension/src/paymentHandler/get-origin-keys.handler.js

This file was deleted.

3 changes: 0 additions & 3 deletions extension/src/paymentHandler/payment-handler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const ValidatorBuilder = require('../validator/validator-builder')
const getPaymentMethodsHandler = require('./get-payment-methods.handler')
const getOriginKeysHandler = require('./get-origin-keys.handler')
const makePaymentHandler = require('./make-payment.handler')
const klarnaMakePaymentHandler = require('./klarna-make-payment.handler')
const submitPaymentDetailsHandler = require('./submit-payment-details.handler')
Expand Down Expand Up @@ -50,8 +49,6 @@ function _getPaymentHandlers (paymentObject) {
return []

const handlers = []
if (paymentObject.custom.fields.getOriginKeysRequest && !paymentObject.custom.fields.getOriginKeysResponse)
handlers.push(getOriginKeysHandler)
if (paymentObject.custom.fields.getPaymentMethodsRequest && !paymentObject.custom.fields.getPaymentMethodsResponse)
handlers.push(getPaymentMethodsHandler)
if (paymentObject.custom.fields.makePaymentRequest && !paymentObject.custom.fields.makePaymentResponse) {
Expand Down
6 changes: 0 additions & 6 deletions extension/src/service/web-component-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ const packageJson = require('../../package.json')

const config = configLoader.load()

function getOriginKeys (getOriginKeysRequestObj) {
return callAdyen(`${config.adyen.apiBaseUrl}/originKeys`,
extendRequestObjWithApplicationInfo(getOriginKeysRequestObj))
}

function getPaymentMethods (getPaymentMethodsRequestObj) {
return callAdyen(`${config.adyen.apiBaseUrl}/paymentMethods`,
extendRequestObjWithApplicationInfo(getPaymentMethodsRequestObj))
Expand Down Expand Up @@ -82,7 +77,6 @@ function buildRequest (requestObj) {
}

module.exports = {
getOriginKeys,
getPaymentMethods,
makePayment,
submitAdditionalPaymentDetails,
Expand Down
3 changes: 1 addition & 2 deletions extension/src/validator/error-messages.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module.exports = {
GET_ORIGIN_KEYS_REQUEST_INVALID_JSON: 'getOriginKeysRequest does not contain valid JSON.',
GET_PAYMENT_METHODS_REQUEST_INVALID_JSON: 'getOriginKeysRequest does not contain valid JSON.',
GET_PAYMENT_METHODS_REQUEST_INVALID_JSON: 'getPaymentMethodsRequest does not contain valid JSON.',
MAKE_PAYMENT_REQUEST_INVALID_JSON: 'makePaymentRequest does not contain valid JSON.',
// eslint-disable-next-line max-len
SUBMIT_ADDITIONAL_PAYMENT_DETAILS_REQUEST_INVALID_JSON: 'submitAdditionalPaymentDetailsRequest does not contain valid JSON.',
Expand Down
2 changes: 0 additions & 2 deletions extension/src/validator/validator-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ function withPayment (paymentObject) {
validateRequestFields () {
if (!paymentObject.custom)
return this
if (!pU.isValidJSON(paymentObject.custom.fields.getOriginKeysRequest))
errors.getOriginKeysRequest = errorMessages.GET_ORIGIN_KEYS_REQUEST_INVALID_JSON
if (!pU.isValidJSON(paymentObject.custom.fields.getPaymentMethodsRequest))
errors.getPaymentMethodsRequest = errorMessages.GET_PAYMENT_METHODS_REQUEST_INVALID_JSON
if (!pU.isValidJSON(paymentObject.custom.fields.makePaymentRequest))
Expand Down
42 changes: 20 additions & 22 deletions extension/test/e2e/credit-card-3ds-native.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const ctpClientBuilder = require('../../src/ctp')
const { routes } = require('../../src/routes')
const configBuilder = require('../../src/config/config')
const httpUtils = require('../../src/utils')
const { assertPayment, createPaymentWithOriginKeyResponse, initPuppeteerBrowser } = require('./e2e-test-utils')
const { assertPayment, createPayment, initPuppeteerBrowser } = require('./e2e-test-utils')
const MakePaymentFormPage = require('./pageObjects/CreditCardMakePaymentFormPage')
const RedirectPaymentFormPage = require('./pageObjects/RedirectPaymentFormPage')
const CreditCardNativePage = require('./pageObjects/CreditCard3dsNativePage')
Expand Down Expand Up @@ -63,51 +63,51 @@ describe('::creditCardPayment3dsNative::', () => {
it(`when credit card issuer is ${name} and credit card number is ${creditCardNumber}, ` +
'then it should successfully finish the payment with 3DS native authentication flow',
async () => {
const baseUrl = configBuilder.load().apiExtensionBaseUrl
const payment = await createPaymentWithOriginKeyResponse(ctpClient, baseUrl)
const { getOriginKeysResponse: getOriginKeysResponseString } = payment.custom.fields
const getOriginKeysResponse = await JSON.parse(getOriginKeysResponseString)
const config = configBuilder.load()
const baseUrl = config.apiExtensionBaseUrl
const clientKey = config.adyen.clientKey
const payment = await createPayment(ctpClient)

const browserTab = await browser.newPage()

const paymentAfterMakePayment = await makePayment({
browserTab,
baseUrl,
getOriginKeysResponse,
creditCardNumber,
creditCardDate,
creditCardCvc,
payment
payment,
clientKey
})

const paymentAfterIdentifyShopper = await identifyShopper({
payment: paymentAfterMakePayment, browserTab, baseUrl, getOriginKeysResponse
payment: paymentAfterMakePayment, browserTab, baseUrl
})

const paymentAfterAuthentication = await performChallengeFlow({
payment: paymentAfterIdentifyShopper,
browserTab,
baseUrl,
getOriginKeysResponse
baseUrl
})

assertPayment(paymentAfterAuthentication)
})
})

async function makePayment ({
browserTab, baseUrl, getOriginKeysResponse,
browserTab, baseUrl,
creditCardNumber,
creditCardDate,
creditCardCvc, payment
creditCardCvc, payment,
clientKey
}) {
const makePaymentFormPage = new MakePaymentFormPage(browserTab, baseUrl)
await makePaymentFormPage.goToThisPage()
const makePaymentRequest = await makePaymentFormPage.getMakePaymentRequest({
getOriginKeysResponse,
creditCardNumber,
creditCardDate,
creditCardCvc
creditCardCvc,
clientKey
})

const { body: updatedPayment } = await ctpClient.update(ctpClient.builder.payments, payment.id,
Expand All @@ -121,15 +121,15 @@ describe('::creditCardPayment3dsNative::', () => {
}

async function identifyShopper ({
payment, browserTab, baseUrl, getOriginKeysResponse
payment, browserTab, baseUrl
}) {
const { makePaymentResponse: makePaymentResponseString } = payment.custom.fields
const makePaymentResponse = await JSON.parse(makePaymentResponseString)
const redirectPaymentFormPage = new RedirectPaymentFormPage(browserTab, baseUrl)
await redirectPaymentFormPage.goToThisPage()
await redirectPaymentFormPage.redirectToAdyenPaymentPage(getOriginKeysResponse, makePaymentResponse)
await redirectPaymentFormPage.redirectToAdyenPaymentPage(makePaymentResponse)

await browserTab.waitFor(2000)
await browserTab.waitForTimeout(2000)

const additionalPaymentDetailsInput = await browserTab.$('#adyen-additional-payment-details')
const additionalPaymentDetailsString = await browserTab.evaluate(el => el.value, additionalPaymentDetailsInput)
Expand All @@ -144,19 +144,17 @@ describe('::creditCardPayment3dsNative::', () => {
}

async function performChallengeFlow ({
payment, browserTab, baseUrl, getOriginKeysResponse
payment, browserTab, baseUrl
}) {
// Submit additional details 1
const { submitAdditionalPaymentDetailsResponse: submitAdditionalPaymentDetailsResponseString }
= payment.custom.fields
const submitAdditionalPaymentDetailsResponse1 = await JSON.parse(submitAdditionalPaymentDetailsResponseString)
const redirectPaymentFormPage = new RedirectPaymentFormPage(browserTab, baseUrl)
await redirectPaymentFormPage.goToThisPage()
await redirectPaymentFormPage.redirectToAdyenPaymentPage(
getOriginKeysResponse, submitAdditionalPaymentDetailsResponse1
)
await redirectPaymentFormPage.redirectToAdyenPaymentPage(submitAdditionalPaymentDetailsResponse1)

await browserTab.waitFor(2000)
await browserTab.waitForTimeout(2000)

// Submit additional details 2
const creditCardNativePage = new CreditCardNativePage(browserTab, baseUrl)
Expand Down
Loading

0 comments on commit 6613535

Please sign in to comment.