generated from ecomplus/application-starter
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwebhook.js
139 lines (130 loc) · 4.87 KB
/
webhook.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
const axios = require('axios')
const { firestore } = require('firebase-admin')
// read configured E-Com Plus app data
const getAppData = require('./../../lib/store-api/get-app-data')
const SKIP_TRIGGER_NAME = 'SkipTrigger'
const ECHO_SUCCESS = 'SUCCESS'
const ECHO_SKIP = 'SKIP'
const ECHO_API_ERROR = 'STORE_API_ERR'
exports.post = ({ appSdk }, req, res) => {
// receiving notification from Store API
const { storeId } = req
/**
* Treat E-Com Plus trigger body here
* Ref.: https://developers.e-com.plus/docs/api/#/store/triggers/
*/
const trigger = req.body
// get app configured options
getAppData({ appSdk, storeId })
.then(appData => {
if (
Array.isArray(appData.ignore_triggers) &&
appData.ignore_triggers.indexOf(trigger.resource) > -1
) {
// ignore current trigger
const err = new Error()
err.name = SKIP_TRIGGER_NAME
throw err
}
/* DO YOUR CUSTOM STUFF HERE */
const { resource } = trigger
if ((resource === 'orders' || resource === 'carts') && trigger.action !== 'delete') {
const resourceId = trigger.resource_id || trigger.inserted_id
if (resourceId) {
const url = appData.ni_webhook_uri
console.log(`Trigger for Store #${storeId} ${resource} ${resourceId} => ${url}`)
if (url) {
return appSdk.apiRequest(storeId, `${resource}/${resourceId}.json`)
.then(async ({ response }) => {
let customer
if (resource === 'carts') {
const cart = response.data
if (cart.available && !cart.completed) {
const abandonedCartDelay = (appData.cart_delay || 12) * 1000 * 60
const { customers } = cart
if (customers && customers[0]) {
const { response } = await appSdk.apiRequest(storeId, `customers/${customers[0]}.json`)
customer = response.data
}
if (!(Date.now() - new Date(cart.created_at).getTime() >= abandonedCartDelay)) {
const documentRef = firestore().doc(`cart_to_add/${cart._id}`)
const msDate = new Date(cart.created_at).getTime() + abandonedCartDelay
await documentRef.set({
data: {
storeId,
trigger,
[resource.slice(0, -1)]: cart,
customer
},
url,
storeId,
sendAt: firestore.Timestamp.fromDate(new Date(msDate))
})
return res.send({
status: 400,
text: 'Waiting to send'
})
}
} else {
return res.sendStatus(204)
}
}
if (resource === 'orders' && response.data.status === 'cancelled' && !(response.data.transactions && response.data.transactions.length)) {
response.data.financial_status = {
current: 'voided'
}
} else if (
resource === 'orders' &&
!trigger.fields.includes('financial_status') &&
!trigger.fields.includes('fulfillment_status')
) {
return res.sendStatus(204)
}
console.log(`> Sending ${resource} notification`)
return axios({
method: 'post',
url,
data: {
storeId,
trigger,
[resource.slice(0, -1)]: response.data,
customer
}
})
})
.then(({ status }) => console.log(`> ${status}`))
.catch(console.error)
.finally(() => {
if (!res.headersSent) {
// all done
res.send(ECHO_SUCCESS)
}
})
}
}
}
res.sendStatus(202)
})
.catch(err => {
if (err.name === SKIP_TRIGGER_NAME) {
// trigger ignored by app configuration
res.send(ECHO_SKIP)
} else if (err.appWithoutAuth === true) {
const msg = `Webhook for ${storeId} unhandled without authentication found`
const error = new Error(msg)
error.trigger = JSON.stringify(trigger)
console.error(error)
res.send(msg)
} else {
// console.error(err)
// request to Store API with error response
// return error status code
res.status(500)
const { message } = err
res.send({
error: ECHO_API_ERROR,
message
})
}
})
}