-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathwebhook.js
110 lines (102 loc) · 3.57 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
const FoxyWebhook = require("../../foxy/FoxyWebhook.js");
const { CartValidator } = require("../../foxy/CartValidator.js");
const { DataStore } = require("./DataStore.js");
const { config } = require("../../../config.js");
/**
* Implements a pre-payment webhook for use with Foxy.io and OrderDesk
*
* https://wiki.foxycart.com/v/2.0/pre_payment_webhook
*
* @param {Object} body parsed of the request received from Foxy
* @returns {Response} to the pre payment request.
*/
async function prePayment(body) {
const datastore = getDataStore();
const cartValidator = new CartValidator();
cartValidator.skipFromEnv();
const pairs = await buildPairs(body, FoxyWebhook, datastore);
// Check Prices
const invalidPrice = pairs.filter(p => !cartValidator.validPrice(...p));
const priceDetail = FoxyWebhook.messagePriceMismatch(invalidPrice);
const invalidInventory = pairs.filter(p => !cartValidator.validInventory(...p));
const inventoryDetail = FoxyWebhook.messageInsufficientInventory(invalidInventory);
if (invalidInventory.length || invalidPrice.length) {
return response([inventoryDetail, priceDetail].filter(m => m.length > 0).join('\n'));
} else {
return response();
}
}
/**
* Process a transaction/created Foxy Webhook.
*
* @param {Object} body the parsed body of the Foxy request.
* @returns {Response}
*/
async function transactionCreated(body) {
if (config.datastore.skipUpdate.inventory === '__ALL__' ) {
return response();
}
try {
const datastore = getDataStore();
const pairs = await buildPairs(body, FoxyWebhook, datastore);
const updated = pairs.map(p => ({...p[1],
stock: Number(p[1].inventory) - Number(p[0].quantity), // Notice that OrderDesk inventory field is "stock"
}));
const result = await datastore.updateInventoryItems(updated);
if (result.status === 'success') {
return response();
} else {
return response('Internal Server Error', 500);
}
} catch (e) {
console.error('Could not update inventory', e.name, e.message);
return response('Internal Server Error', 500);
}
}
/**
* Prepares lists of items and creates pairs of related items.
*
* It builds the list of cart items, getting them from
*
* @param {Object} body of the Foxy Webhook Request Event.
* @param {Object} foxyWebhook that can retrieve the cart items.
* @param {Object} datastore that can fetch the OrderDesk items.
* @returns {Array<Array<Object,Object>>} Array of paired cart and canonical items.
*/
async function buildPairs(body, foxyWebhook, datastore) {
const cartItems = foxyWebhook.getItems(body);
if (!cartItems || !cartItems.length) {
return [];
}
let canonicalItems = await datastore.fetchInventoryItems(cartItems.map(i => i.code));
canonicalItems = canonicalItems.map(datastore.convertToCanonical.bind(datastore));
return codePairs(cartItems, canonicalItems);
}
/**
* Creates pairs of items based on their code field.
*
* @param {Array<Object>} listA of objects with a code field.
* @param {Array<Object>} listB of objects with a code field.
* @returns {Array<Array<Object,Object>>} Array of paired cart and canonical items.
*/
function codePairs(listA, listB) {
return listA.map(a => [a, listB.find(b => b.code === a.code)])
}
/**
* Creates an instance of the Datastore with the credentials.
*
* @returns {Object} the OrderDesk datastore.
*/
function getDataStore() {
const odConfig = config.datastore.provider.orderDesk;
return new DataStore(
odConfig.apiKey,
odConfig.storeId
);
}
const response = FoxyWebhook.response;
module.exports = {
prePayment,
response,
transactionCreated,
}