1
1
conditions :
2
- check_powder_protocols :
2
+ create_products :
3
+ description : Create products for order items in state "pending"
3
4
default : true
5
+ check : |
6
+ function() {
7
+ debug(context, "create_products check")
8
+ return true
9
+ }
10
+ true :
11
+ action : |
12
+ function() {
13
+ pendingOrderItems = context.OrderItems.filter(oi => oi.State === 'pending')
14
+
15
+ context.Products = pendingOrderItems.map(oi => ({
16
+ Ref: oi.Ref,
17
+ Rank: oi.Rank,
18
+ OrderItemRef: oi.Ref,
19
+ OrderType: oi.OrderType,
20
+ ProductType: oi.ProductType,
21
+ Amount: oi.Amount,
22
+ Concentration: oi.Concentration,
23
+ Solvent: oi.Solvent,
24
+ State: 'pending'
25
+ }));
26
+ }
27
+ next : check_powder_protocols
28
+ check_powder_protocols :
4
29
description : Check if there are any powder protocols among the products.
5
30
check : |
6
31
function () {
7
- if (debug) ( debug(context, "I'm in check_powder_protocols") )
8
- return context.OrderItems.find(p => p.ProductType === 'powder') !== undefined;
32
+ return context.Products.find(p => p.ProductType === 'powder') !== undefined;
9
33
}
10
34
true :
11
35
description : Fail all powder products and their corresponding order items.
12
36
action : |
13
37
function () {
14
- const powderOrderItems = context.OrderItems .filter(p => p.ProductType === 'powder');
15
- powderOrderItems .forEach(p => {
38
+ const powderProducts = context.Products .filter(p => p.ProductType === 'powder');
39
+ powderProducts .forEach(p => {
16
40
p.State = 'fail';
17
- const orderItem = context.OrderItems.find(oi => oi.Ref === p.OrderItemRef);
18
- if (orderItem) {
19
- orderItem.State = 'fail';
20
- }
21
41
});
22
42
}
23
43
next : check_mixed_solvents
@@ -27,21 +47,41 @@ conditions:
27
47
description : Check if there are mixed solvents or concentrations among the solution order items.
28
48
check : |
29
49
function () {
30
- const pendingOrderItems = context.OrderItems.filter(oi => oi.State === 'pending');
31
- const primaryOrderItem = pendingOrderItems.find(oi => oi.OrderType === 'primary');
32
- const earlySolutionOrderItems = pendingOrderItems.filter(oi => oi.OrderType !== 'primary' && oi.ProductType === 'solution');
33
- return earlySolutionOrderItems.find(oi => oi.Solvant !== primaryOrderItem.Solvant || oi.Concentration !== primaryOrderItem.Concentration) !== undefined;
50
+ // get all pending products
51
+
52
+ const pendingProducts = context.Products.filter(p => p.State === 'pending');
53
+ if (pendingProducts == null) {
54
+ return false
55
+ }
56
+
57
+ // take solvent and concentration or order item with order type primaryOrderItem
58
+ primaryProduct = context.Products.find(oi => oi.OrderType === 'primary') ?? pendingProducts[0]
59
+
60
+ concentration = primaryProduct.Concentration
61
+ solvent = primaryProduct.Solvent
62
+
63
+ // check if there are any order items with different solvent or concentration
64
+ return pendingProducts.find(p => p.Solvent !== solvent || p.Concentration !== concentration) !== undefined;
34
65
}
35
66
true :
36
67
description : Fail order items and products with mixed solvents or concentrations.
37
68
action : |
38
69
function () {
39
- const pendingOrderItems = context.OrderItems.filter(oi => oi.State === 'pending');
40
- const primaryOrderItem = pendingOrderItems.find(oi => oi.OrderType === 'primary');
41
- const failedOrderItems = pendingOrderItems.filter(oi => oi.OrderType !== 'primary' && (oi.Solvant !== primaryOrderItem.Solvant || oi.Concentration !== primaryOrderItem.Concentration));
42
- failedOrderItems.forEach(oi => oi.State = 'fail');
43
- const failedProducts = context.Products.filter(p => failedOrderItems.find(oi => oi.Ref === p.OrderItemRef) !== undefined);
44
- failedProducts.forEach(p => p.State = 'fail');
70
+ // get all pending products
71
+ const pendingProducts = context.Products.filter(p => p.State === 'pending');
72
+
73
+ // take solvent and concentration or order item with order type primaryOrderItem
74
+ primaryOrderItem = context.OrderItems.find(oi => oi.OrderType === 'primary') ?? context.OrderItems[0]
75
+
76
+ concentration = primaryOrderItem[0].Concentration
77
+ solvent = primaryOrderItem[0].Solvent
78
+
79
+ // set state to failed for all products with different solvent or concentration
80
+ pendingProducts.forEach(p => {
81
+ if (p.Solvent !== solvent || p.Concentration !== concentration) {
82
+ p.State = 'fail';
83
+ }
84
+ });
45
85
}
46
86
next : check_overflow
47
87
false :
@@ -50,16 +90,15 @@ conditions:
50
90
description : Check if the total required amount exceeds the container amount.
51
91
check : |
52
92
function () {
53
- const pendingOrderItems = context.OrderItems .filter(oi => oi.State === 'pending');
54
- const totalRequiredAmount = pendingOrderItems .reduce((sum, oi) => sum + oi.Amount, 0);
93
+ const pendingProducts = context.Products .filter(oi => oi.State === 'pending');
94
+ const totalRequiredAmount = pendingProducts .reduce((sum, oi) => sum + oi.Amount, 0);
55
95
return totalRequiredAmount > context.Container.Amount;
56
96
}
57
97
true :
58
98
description : Fail all products and order items due to container overflow.
59
99
action : |
60
100
function () {
61
101
context.Products.forEach(p => p.State = 'fail');
62
- context.OrderItems.forEach(oi => oi.State = 'fail');
63
102
}
64
103
terminate : true
65
104
false :
@@ -68,24 +107,27 @@ conditions:
68
107
description : Check if the actual amount is less than the required amount.
69
108
check : |
70
109
function () {
71
- const pendingOrderItems = context.OrderItems .filter(oi => oi.State === 'pending');
72
- const totalRequiredAmount = pendingOrderItems .reduce((sum, oi) => sum + oi.Amount, 0);
110
+ const pendingProducts = context.Products .filter(oi => oi.State === 'pending');
111
+ const totalRequiredAmount = pendingProducts .reduce((sum, oi) => sum + oi.Amount, 0);
73
112
const diff = context.Container.Amount - totalRequiredAmount;
74
113
return diff < 0;
75
114
}
76
115
true :
77
116
description : Fail the lowest-ranked order items and their corresponding products until the remaining amount can be fulfilled.
78
117
action : |
79
118
function () {
80
- const pendingOrderItems = context.OrderItems.filter(oi => oi.State === 'pending');
81
- const totalRequiredAmount = pendingOrderItems.reduce((sum, oi) => sum + oi.Amount, 0);
82
- const diff = context.Container.Amount - totalRequiredAmount;
83
- const sortedOrderItems = pendingOrderItems.sort((a, b) => a.Ranking - b.Ranking);
84
- let remainingAmount = -diff;
85
- for (const orderItem of sortedOrderItems) {
86
- if (remainingAmount >= orderItem.Amount) {
87
- remainingAmount -= orderItem.Amount;
88
- orderItem.State = 'fail';
119
+ const pendingProducts = context.Products.filter(oi => oi.State === 'pending');
120
+ const totalRequiredAmount = pendingProducts.reduce((sum, oi) => sum + oi.Amount, 0);
121
+ const diff = totalRequiredAmount - context.Container.Amount;
122
+
123
+ // sort products by rank in ascending order, so we can fail the lowest-ranked ones first
124
+ // (rank 1 failed first, rank 2 failed second, etc.)
125
+ const sortedProducts = pendingProducts.sort((a, b) => a.Ranking - b.Ranking);
126
+
127
+ for (const p of sortedProducts) {
128
+ if (diff > 0) {
129
+ diff -= p.Amount;
130
+ p.State = 'fail';
89
131
} else {
90
132
break;
91
133
}
@@ -94,39 +136,27 @@ conditions:
94
136
# After failing some order items, we might have a certain amount left over
95
137
# It might be less than required by any failed order item, but still usable for a spare
96
138
next : check_leftovers
97
- false :
98
- next : check_amount_equal_to_required
99
- check_amount_equal_to_required :
100
- description : Check if the actual amount is equal to the required amount.
101
- check : |
102
- function () {
103
- const pendingOrderItems = context.OrderItems.filter(oi => oi.State === 'pending');
104
- const totalRequiredAmount = pendingOrderItems.reduce((sum, oi) => sum + oi.Amount, 0);
105
- const diff = context.Container.Amount - totalRequiredAmount;
106
- return diff === 0;
107
- }
108
- true :
109
- terminate : true
110
139
false :
111
140
next : check_amount_more_than_required
112
141
check_amount_more_than_required :
113
142
description : Check if the actual amount is more than the required amount.
114
143
check : |
115
144
function () {
116
- const pendingOrderItems = context.OrderItems .filter(oi => oi.State === 'pending');
117
- const totalRequiredAmount = pendingOrderItems .reduce((sum, oi) => sum + oi.Amount, 0);
145
+ const pendingProducts = context.Products .filter(oi => oi.State === 'pending');
146
+ const totalRequiredAmount = pendingProducts .reduce((sum, oi) => sum + oi.Amount, 0);
118
147
return context.Container.Amount - totalRequiredAmount > 0;
119
148
}
120
149
true :
121
150
next : check_remainder_less_than_50
122
151
false :
152
+ # Amount equals to required if we got here
123
153
terminate : true
124
154
check_leftovers :
125
155
description : Check if there are any non-consumed leftovers.
126
156
check : |
127
157
function () {
128
- const pendingOrderItems = context.OrderItems .filter(oi => oi.State === 'pending');
129
- return context.Container.Amount > pendingOrderItems .reduce((sum, oi) => sum + oi.Amount, 0);
158
+ const pendingProducts = context.Products .filter(oi => oi.State === 'pending');
159
+ return context.Container.Amount > pendingProducts .reduce((sum, oi) => sum + oi.Amount, 0);
130
160
}
131
161
true :
132
162
next : check_remainder_less_than_50
@@ -136,8 +166,8 @@ conditions:
136
166
description : Check if the remainder is less than 50 μl.
137
167
check : |
138
168
function () {
139
- const pendingOrderItems = context.OrderItems .filter(oi => oi.State === 'pending');
140
- const totalRequiredAmount = pendingOrderItems .reduce((sum, oi) => sum + oi.Amount, 0);
169
+ const pendingProducts = context.Products .filter(oi => oi.State === 'pending');
170
+ const totalRequiredAmount = pendingProducts .reduce((sum, oi) => sum + oi.Amount, 0);
141
171
const remainder = context.Container.Amount - totalRequiredAmount;
142
172
return remainder < 50;
143
173
}
@@ -149,22 +179,24 @@ conditions:
149
179
description : Check if the remainder is between 50 μl and 950 μl.
150
180
check : |
151
181
function () {
152
- const pendingOrderItems = context.OrderItems .filter(oi => oi.State === 'pending');
153
- const totalRequiredAmount = pendingOrderItems .reduce((sum, oi) => sum + oi.Amount, 0);
182
+ const pendingProducts = context.Products .filter(oi => oi.State === 'pending');
183
+ const totalRequiredAmount = pendingProducts .reduce((sum, oi) => sum + oi.Amount, 0);
154
184
const remainder = context.Container.Amount - totalRequiredAmount;
155
185
return remainder >= 50 && remainder < 950;
156
186
}
157
187
true :
158
188
description : Create a spare tube with the remaining amount.
159
189
action : |
160
190
function () {
161
- const pendingOrderItems = context.OrderItems .filter(oi => oi.State === 'pending');
162
- const remainder = context.Container.Amount - pendingOrderItems .reduce((sum, oi) => sum + oi.Amount, 0);
191
+ const pendingProducts = context.Products .filter(oi => oi.State === 'pending');
192
+ const remainder = context.Container.Amount - pendingProducts .reduce((sum, oi) => sum + oi.Amount, 0);
163
193
const newProduct = {
164
194
Ref: context.Products.length + 1,
165
195
OrderItemRef: null,
166
196
ProductType: 'solution',
167
197
Amount: remainder,
198
+ Concentration: pendingProducts[0].Concentration,
199
+ Solvent: pendingProducts[0].Solvent,
168
200
State: 'pending'
169
201
};
170
202
context.Products.push(newProduct);
@@ -176,29 +208,34 @@ conditions:
176
208
description : Check if the remainder is between 950 μl and 1800 μl.
177
209
check : |
178
210
function () {
179
- const pendingOrderItems = context.OrderItems .filter(oi => oi.State === 'pending');
180
- const totalRequiredAmount = pendingOrderItems .reduce((sum, oi) => sum + oi.Amount, 0);
211
+ const pendingProducts = context.Products .filter(oi => oi.State === 'pending');
212
+ const totalRequiredAmount = pendingProducts .reduce((sum, oi) => sum + oi.Amount, 0);
181
213
const remainder = context.Container.Amount - totalRequiredAmount;
182
214
return remainder >= 950 && remainder <= 1800;
183
215
}
184
216
true :
185
217
description : Create two spare tubes, one with 900 μl and another with the remaining amount.
186
218
action : |
187
219
function () {
188
- const pendingOrderItems = context.OrderItems.filter(oi => oi.State === 'pending');
189
- const remainder = context.Container.Amount - pendingOrderItems.reduce((sum, oi) => sum + oi.Amount, 0);
220
+ const pendingProducts = context.Products.filter(oi => oi.State === 'pending');
221
+ const totalRequiredAmount = pendingProducts.reduce((sum, oi) => sum + oi.Amount, 0);
222
+ const remainder = context.Container.Amount - totalRequiredAmount;
190
223
const newProduct1 = {
191
224
Ref: context.Products.length + 1,
192
225
OrderItemRef: null,
193
226
ProductType: 'solution',
194
227
Amount: 900,
228
+ Concentration: pendingProducts[0].Concentration,
229
+ Solvent: pendingProducts[0].Solvent,
195
230
State: 'pending'
196
231
};
197
232
const newProduct2 = {
198
233
Ref: context.Products.length + 2,
199
234
OrderItemRef: null,
200
235
ProductType: 'solution',
201
236
Amount: remainder - 900,
237
+ Concentration: pendingProducts[0].Concentration,
238
+ Solvent: pendingProducts[0].Solvent,
202
239
State: 'pending'
203
240
};
204
241
context.Products.push(newProduct1, newProduct2);
@@ -208,8 +245,6 @@ conditions:
208
245
description : Fail all order items with comment
209
246
action : |
210
247
function () {
211
- pendingOrderItems = context.OrderItems.filter(oi => oi.State === 'pending');
212
- pendingOrderItems.forEach(ppi => ppi.State = "fail")
213
- context.Products = []
248
+ context.Products.filter(p => p.State === 'pending').forEach(p => p.State = "fail")
214
249
}
215
250
terminate : true
0 commit comments