-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
99 lines (82 loc) · 2.78 KB
/
index.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
export const filterOffers = (offers, items) =>
Object.keys(offers).reduce((acc, offerKey) => {
const offer = offers[offerKey];
const allowed = !Object.keys(offer.combination).find(
key => !(acc.availableItems.hasOwnProperty(key) && acc.availableItems[key] >= offer.combination[key])
);
(allowed ? acc.allowed : acc.overlapping).push(offerKey);
if (allowed) {
Object.keys(offer.combination).forEach(key => {
if (acc.availableItems.hasOwnProperty(key)) {
acc.availableItems[key]--;
if (acc.availableItems[key]<=0) {
delete acc.availableItems[key];
}
}
acc.allowedPerItem[key] = [...(acc.allowedPerItem.hasOwnProperty(key) ? acc.allowedPerItem[key] : []), offerKey];
});
}
return acc;
}, {
allowed: [],
overlapping: [],
allowedPerItem: {},
availableItems: Object.assign({}, items),
});
export const calcOfferGain = (allowed, offers, itemValues) => {
let gain = 0;
allowed.forEach(offerKey => {
const offer = offers[offerKey];
let original = 0;
Object.keys(offer.combination).forEach(itemId => {
const qty = offer.combination[itemId];
original += qty * itemValues[itemId];
});
// fixed price
if (offer.hasOwnProperty('value')) {
gain += offer.value - original;
}
// percentage
else if (offer.hasOwnProperty('pct')) {
gain -= original * (offer[pct] / 100);
}
});
return gain;
};
export const findLeastClearanceNeeded = allowedPerItem =>
Object
.keys(allowedPerItem)
.reduce((acc, curr) => [...acc, allowedPerItem[curr]], [])
.sort((a,b) => a.length - b.length)
.shift();
export const getOverlappingScenarios = (offers, items, itemValues) => {
let offerKeys = Object.keys(offers).reduce((acc, curr) => ({...acc, [curr]: true}), {});
let scenarios = [];
let leastClearanceNeeded;
do {
const includedOffers = Object.keys(offerKeys).reduce((acc, curr) => {
if(offerKeys[curr]) {
acc[curr] = offers[curr];
}
return acc;
}, {});
const {allowed, allowedPerItem} = filterOffers(includedOffers, items);
leastClearanceNeeded = findLeastClearanceNeeded(allowedPerItem);
if (leastClearanceNeeded) {
leastClearanceNeeded.forEach(key => offerKeys[key] = false);
}
const offerGain = calcOfferGain(allowed, offers, itemValues);
scenarios.push({
appliedOffers: allowed,
gain: offerGain,
});
}
while (leastClearanceNeeded);
return scenarios;
}
export const getBestScenario = overlappingScenarios =>
overlappingScenarios
.sort((a,b) => a.gain - b.gain)
.shift();
export const getBestOffers = (applicableOffers, chosenItems, itemValues) =>
getBestScenario(getOverlappingScenarios(applicableOffers, chosenItems, itemValues));