Skip to content

Commit b2d15b9

Browse files
authored
Merge pull request #1 from comwrap/starter-kit-2
Update to Adobe Integration started kit v.2 and fix compartibility issues
2 parents 47d5248 + 6490890 commit b2d15b9

59 files changed

Lines changed: 8315 additions & 4808 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

INSTALL.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ aio console workspace select
5959

6060
Sync your local application with the App Builder project using the following command:
6161
```bash
62-
aio app use
63-
# Choose the option 'm' (merge)
62+
aio app use --merge
63+
# Choose the option 'm' (merge) to merge configurations
6464
```
6565

6666
### Deploy
@@ -138,7 +138,7 @@ Hubspot is an integrated system and to connect Adobe Commerce with Hubspot you n
138138
139139
### Configuration
140140
141-
Go to Data Management -> Integrations and create a new App.
141+
Go to Data Management -> Data Integration and create a new App.
142142
143143
Inside of the created app you can switch to "Auth" tab and receive an Access Token.
144144
@@ -156,6 +156,16 @@ COMMERCE_HUBSPOT_CONTACT_ID_FIELD=
156156
157157
It's an Adobe Commerce customer custom attribute code, which will be used to save Hubspot Customer ID, so in case if customer already being exported to Hubspot, system will perform Update and not Create action
158158
159+
For Full Data Synchronization, please also define:
160+
161+
```
162+
// Adobe Commerce Group ID for customers. (1 - General Group)
163+
HUBSPOT_FULL_IMPORT_CONTACT_GROUP_ID=1
164+
// Adobe Commerce Website Code to import
165+
HUBSPOT_FULL_IMPORT_CONTACT_WEBSITE=
166+
```
167+
168+
159169
### Hubspot -> Adobe Commerce sync
160170
161171
Part of the tion HubSpot integration involves enabling the synchronization of changes made in HubSpot back to Adobe Commerce.

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,8 @@ For more information pls go to
4444

4545
Api Mesh file for configuration you can find at mesh.json file.
4646

47+
## Trouble shooting
48+
49+
### The Backoffice Customer Sync event returns a 400 error.
50+
51+
If you encounter a 400 response code for the event be-observer.customer_update, please validate your customer's required fields. Since every setup can vary, ensure that your required fields match across the Adobe Commerce Customer & Customer Address, actions/customer/external/updated/schema.json Schema, and HubSpot Workflows script.

actions/auth.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
Copyright 2024 Adobe. All rights reserved.
3+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License. You may obtain a copy
5+
of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
7+
Unless required by applicable law or agreed to in writing, software distributed under
8+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
OF ANY KIND, either express or implied. See the License for the specific language
10+
governing permissions and limitations under the License.
11+
*/
12+
13+
const { Core } = require('@adobe/aio-sdk')
14+
const logger = Core.Logger('auth', { level: 'info' })
15+
/**
16+
*
17+
* @param {object} params - Environment params from the IO Runtime request
18+
* @param {Array} expected - expected keys inside the params
19+
* @returns {Array} - returns the missing params
20+
*/
21+
function checkIfMissing (params, expected) {
22+
return expected.filter(value => !params[value]).map(key => {
23+
return {
24+
error: true,
25+
message: `Missing ${key} in params`,
26+
key
27+
}
28+
})
29+
}
30+
31+
/**
32+
*
33+
* @param {object} params - Environment params from the IO Runtime request
34+
* @param {Array} expected - list of keys
35+
* @throws {Error} - throws error if the params are missing
36+
*/
37+
function validateParams (params, expected) {
38+
// check if missing
39+
const validated = checkIfMissing(params, expected)
40+
if (validated.length > 0) {
41+
throw new Error(`Expected parameters are missing ${validated.map(value => value.key).join(', ')}`)
42+
}
43+
}
44+
45+
/**
46+
* This function returns the auth object based on the params
47+
* @param {object} params - Environment params from the IO Runtime request
48+
* @returns {object} - returns the auth object for the request
49+
* @throws {Error} - throws error if the params are missing
50+
*/
51+
function fromParams (params) {
52+
// `aio app dev` compatibility: inputs mapped to undefined env vars come as $<input_name> in dev mode, but as '' in prod mode
53+
if (params.COMMERCE_CONSUMER_KEY && params.COMMERCE_CONSUMER_KEY !== '$COMMERCE_CONSUMER_KEY') {
54+
logger.info('Commerce client is using Commerce OAuth1 authentication')
55+
validateParams(params,
56+
['COMMERCE_CONSUMER_KEY', 'COMMERCE_CONSUMER_SECRET', 'COMMERCE_ACCESS_TOKEN', 'COMMERCE_ACCESS_TOKEN_SECRET'])
57+
const { COMMERCE_CONSUMER_KEY: consumerKey, COMMERCE_CONSUMER_SECRET: consumerSecret, COMMERCE_ACCESS_TOKEN: accessToken, COMMERCE_ACCESS_TOKEN_SECRET: accessTokenSecret } = params
58+
return {
59+
commerceOAuth1: {
60+
consumerKey,
61+
consumerSecret,
62+
accessToken,
63+
accessTokenSecret
64+
}
65+
}
66+
}
67+
68+
// `aio app dev` compatibility: inputs mapped to undefined env vars come as $<input_name> in dev mode, but as '' in prod mode
69+
if (params.OAUTH_CLIENT_ID && params.OAUTH_CLIENT_ID !== '$OAUTH_CLIENT_ID') {
70+
logger.info('Commerce client is using IMS OAuth authentication')
71+
validateParams(params,
72+
['OAUTH_CLIENT_ID', 'OAUTH_CLIENT_SECRET', 'OAUTH_SCOPES'])
73+
const { OAUTH_CLIENT_ID: clientId, OAUTH_CLIENT_SECRET: clientSecret, OAUTH_SCOPES: scopes } = params
74+
75+
const imsProps = {
76+
clientId,
77+
clientSecret,
78+
scopes
79+
}
80+
if (params.OAUTH_HOST) {
81+
return {
82+
ims: {
83+
...imsProps,
84+
host: params.OAUTH_HOST
85+
}
86+
}
87+
}
88+
return {
89+
ims: imsProps
90+
}
91+
}
92+
93+
throw new Error('Unknown auth type, supported IMS OAuth or Commerce OAuth1. Please review documented auth types')
94+
}
95+
96+
module.exports = {
97+
validateParams,
98+
fromParams
99+
}

actions/customer/commerce-customer-api-client.js

Lines changed: 27 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag
1010
governing permissions and limitations under the License.
1111
*/
1212

13-
const { getCommerceOauthClient } = require('../oauth1a')
13+
const { getClient } = require('../oauth1a')
1414
const { Core } = require('@adobe/aio-sdk')
1515
const logger = Core.Logger('commerce-consumer-api-client', { level: 'info' })
1616

@@ -19,20 +19,14 @@ const logger = Core.Logger('commerce-consumer-api-client', { level: 'info' })
1919
*
2020
* @returns {object} - API response object
2121
* @param {string} baseUrl - Adobe commerce rest api base url
22-
* @param {string} consumerKey - Adobe commerce integration consumer key
23-
* @param {string} consumerSecret - Adobe commerce integration consumer secret
24-
* @param {string} accessToken - Adobe commerce integration access token
25-
* @param {string} accessTokenSecret - Adobe commerce integration access token secret
22+
* @param {object} params - Environment params from the IO Runtime request
2623
* @param {object} data - Adobe commerce api payload
2724
*/
28-
async function createCustomer (baseUrl, consumerKey, consumerSecret, accessToken, accessTokenSecret, data) {
29-
const client = getCommerceOauthClient(
25+
async function createCustomer (baseUrl, params, data) {
26+
const client = getClient(
3027
{
3128
url: baseUrl,
32-
consumerKey,
33-
consumerSecret,
34-
accessToken,
35-
accessTokenSecret
29+
params
3630
},
3731
logger
3832
)
@@ -50,20 +44,14 @@ async function createCustomer (baseUrl, consumerKey, consumerSecret, accessToken
5044
*
5145
* @returns {object} - API response object
5246
* @param {string} baseUrl - Adobe commerce rest api base url
53-
* @param {string} consumerKey - Adobe commerce integration consumer key
54-
* @param {string} consumerSecret - Adobe commerce integration consumer secret
55-
* @param {string} accessToken - Adobe commerce integration access token
56-
* @param {string} accessTokenSecret - Adobe commerce integration access token secret
47+
* @param {object} params - Environment params from the IO Runtime request
5748
* @param {object} data - Adobe commerce api payload
5849
*/
59-
async function importCustomerBatch (baseUrl, consumerKey, consumerSecret, accessToken, accessTokenSecret, data) {
60-
const client = getCommerceOauthClient(
50+
async function importCustomerBatch (baseUrl, params, data) {
51+
const client = getClient(
6152
{
6253
url: baseUrl,
63-
consumerKey,
64-
consumerSecret,
65-
accessToken,
66-
accessTokenSecret
54+
params
6755
},
6856
logger
6957
)
@@ -91,24 +79,17 @@ async function importCustomerBatch (baseUrl, consumerKey, consumerSecret, access
9179
*
9280
* @returns {object} - API response object
9381
* @param {string} baseUrl - Adobe commerce rest api base url
94-
* @param {string} consumerKey - Adobe commerce integration consumer key
95-
* @param {string} consumerSecret - Adobe commerce integration consumer secret
96-
* @param {string} accessToken - Adobe commerce integration access token
97-
* @param {string} accessTokenSecret - Adobe commerce integration access token secret
82+
* @param {object} params - Environment params from the IO Runtime request
9883
* @param {object} data - Adobe commerce api payload
9984
*/
100-
async function updateCustomer (baseUrl, consumerKey, consumerSecret, accessToken, accessTokenSecret, data) {
101-
const client = getCommerceOauthClient(
85+
async function updateCustomer (baseUrl, params, data) {
86+
const client = getClient(
10287
{
10388
url: baseUrl,
104-
consumerKey,
105-
consumerSecret,
106-
accessToken,
107-
accessTokenSecret
89+
params
10890
},
10991
logger
11092
)
111-
11293
return await client.put(
11394
`customers/${data.customer.id}`,
11495
JSON.stringify(data),
@@ -122,20 +103,14 @@ async function updateCustomer (baseUrl, consumerKey, consumerSecret, accessToken
122103
*
123104
* @returns {object} - API response object
124105
* @param {string} baseUrl - Adobe commerce rest api base url
125-
* @param {string} consumerKey - Adobe commerce integration consumer key
126-
* @param {string} consumerSecret - Adobe commerce integration consumer secret
127-
* @param {string} accessToken - Adobe commerce integration access token
128-
* @param {string} accessTokenSecret - Adobe commerce integration access token secret
106+
* @param {object} params - Environment params from the IO Runtime request
129107
* @param {number} id - Id
130108
*/
131-
async function deleteCustomer (baseUrl, consumerKey, consumerSecret, accessToken, accessTokenSecret, id) {
132-
const client = getCommerceOauthClient(
109+
async function deleteCustomer (baseUrl, params, id) {
110+
const client = getClient(
133111
{
134112
url: baseUrl,
135-
consumerKey,
136-
consumerSecret,
137-
accessToken,
138-
accessTokenSecret
113+
params
139114
},
140115
logger
141116
)
@@ -147,20 +122,14 @@ async function deleteCustomer (baseUrl, consumerKey, consumerSecret, accessToken
147122
*
148123
* @returns {object} - API response object
149124
* @param {string} baseUrl - Adobe commerce rest api base url
150-
* @param {string} consumerKey - Adobe commerce integration consumer key
151-
* @param {string} consumerSecret - Adobe commerce integration consumer secret
152-
* @param {string} accessToken - Adobe commerce integration access token
153-
* @param {string} accessTokenSecret - Adobe commerce integration access token secret
125+
* @param {string} params - Environment params from the IO Runtime request
154126
* @param {object} customerId - Adobe commerce customer ID
155127
*/
156-
async function getCustomer (baseUrl, consumerKey, consumerSecret, accessToken, accessTokenSecret, customerId) {
157-
const client = getCommerceOauthClient(
128+
async function getCustomer (baseUrl, params, customerId) {
129+
const client = getClient(
158130
{
159131
url: baseUrl,
160-
consumerKey,
161-
consumerSecret,
162-
accessToken,
163-
accessTokenSecret
132+
params
164133
},
165134
logger
166135
)
@@ -176,26 +145,17 @@ async function getCustomer (baseUrl, consumerKey, consumerSecret, accessToken, a
176145
*
177146
* @returns {object} - API response object
178147
* @param {string} baseUrl - Adobe commerce rest api base url
179-
* @param {string} consumerKey - Adobe commerce integration consumer key
180-
* @param {string} consumerSecret - Adobe commerce integration consumer secret
181-
* @param {string} accessToken - Adobe commerce integration access token
182-
* @param {string} accessTokenSecret - Adobe commerce integration access token secret
148+
* @param {string} params - Environment params from the IO Runtime request
183149
* @param {string} searchCriteria - Adobe commerce search criteria
184150
*/
185151
async function getCustomerBySearchCriteria (
186152
baseUrl,
187-
consumerKey,
188-
consumerSecret,
189-
accessToken,
190-
accessTokenSecret,
153+
params,
191154
searchCriteria) {
192-
const client = getCommerceOauthClient(
155+
const client = getClient(
193156
{
194157
url: baseUrl,
195-
consumerKey,
196-
consumerSecret,
197-
accessToken,
198-
accessTokenSecret
158+
params
199159
},
200160
logger
201161
)
@@ -211,7 +171,7 @@ module.exports = {
211171
createCustomer,
212172
updateCustomer,
213173
deleteCustomer,
174+
importCustomerBatch,
214175
getCustomer,
215-
getCustomerBySearchCriteria,
216-
importCustomerBatch
176+
getCustomerBySearchCriteria
217177
}

actions/customer/commerce/actions.config.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ consumer:
33
web: 'no'
44
runtime: nodejs:20
55
inputs:
6-
LOG_LEVEL: debug
7-
COMMERCE_HUBSPOT_CONTACT_ID_FIELD: $COMMERCE_HUBSPOT_CONTACT_ID_FIELD
8-
HUBSPOT_ACCESS_TOKEN: $HUBSPOT_ACCESS_TOKEN
6+
LOG_LEVEL: debug
7+
COMMERCE_HUBSPOT_CONTACT_ID_FIELD: $COMMERCE_HUBSPOT_CONTACT_ID_FIELD
8+
HUBSPOT_ACCESS_TOKEN: $HUBSPOT_ACCESS_TOKEN
99
annotations:
10-
require-adobe-auth: true
11-
final: true
10+
require-adobe-auth: true
11+
final: true
1212
created:
1313
function: created/index.js
1414
web: 'no'

actions/customer/commerce/created/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,17 @@ async function main (params) {
4444
const transformedData = transformData(params.data)
4545

4646
logger.debug(`Preprocess data: ${stringParameters(params)}`)
47-
const preProcessed = await preProcess(params, transformedData)
47+
const preProcessed = preProcess(params, transformedData)
4848

4949
logger.debug(`Start sending data: ${JSON.stringify(params)}`)
5050
const result = await sendData(params, transformedData, preProcessed)
51-
logger.debug(`Result from HubSpot request: ${JSON.stringify(result)}`)
5251
if (!result.success) {
5352
logger.error(`Send data failed: ${result.message}`)
5453
return actionErrorResponse(result.statusCode, result.message)
5554
}
5655

5756
logger.debug(`Postprocess data: ${stringParameters(params)}`)
58-
await postProcess(params, result)
57+
postProcess(params, transformedData, preProcessed, result)
5958

6059
logger.debug('Process finished successfully')
6160
return actionSuccessResponse('Customer created successfully')

actions/customer/commerce/created/post.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@ async function postProcess (params, result) {
2424
try {
2525
const response = await updateCustomer(
2626
params.COMMERCE_BASE_URL,
27-
params.COMMERCE_CONSUMER_KEY,
28-
params.COMMERCE_CONSUMER_SECRET,
29-
params.COMMERCE_ACCESS_TOKEN,
30-
params.COMMERCE_ACCESS_TOKEN_SECRET,
27+
params,
3128
{
3229
customer: {
3330
id: params.data.id,

actions/customer/commerce/updated/index.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,10 @@ async function main (params) {
4444
const transformedData = transformData(params.data)
4545

4646
logger.debug(`Preprocess data: ${stringParameters(params)}`)
47-
const preProcessed = await preProcess(params, transformedData)
48-
logger.debug(`Preprocess data result: ${JSON.stringify(preProcessed)}`)
47+
const preProcessed = preProcess(params, transformedData)
4948

5049
logger.debug(`Start sending data: ${JSON.stringify(params)}`)
51-
const result = await sendData(params, preProcessed)
50+
const result = await sendData(params, transformedData, preProcessed)
5251
if (!result.success) {
5352
logger.error(`Send data failed: ${result.message}`)
5453
return actionErrorResponse(result.statusCode, result.message)

0 commit comments

Comments
 (0)