@softwear/latestcollectioncore 1.0.198 → 1.0.199

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -159,10 +159,14 @@ function aggregator({ beginTimestamp, endTimestamp, filterExpression, aggregatio
159
159
  .filter((join) => filterExpression.includes(join[0] + '.'))
160
160
  .map((join) => join[1]);
161
161
  }
162
- const aggregationEvaluator = buildAggregationEvaluator(aggregationExpression);
163
- const aggregationGranularity = Object.entries(globalJoinableTables)
164
- .filter((join) => aggregationExpression.includes(join[0] + '.'))
165
- .map((join) => join[1]);
162
+ // Empty aggregation expression = no groupers → only the totals row
163
+ const totalsOnly = !aggregationExpression;
164
+ const aggregationEvaluator = totalsOnly ? undefined : buildAggregationEvaluator(aggregationExpression);
165
+ const aggregationGranularity = totalsOnly
166
+ ? []
167
+ : Object.entries(globalJoinableTables)
168
+ .filter((join) => aggregationExpression.includes(join[0] + '.'))
169
+ .map((join) => join[1]);
166
170
  const aggregationTrieRoot = {};
167
171
  return function (transaction) {
168
172
  if (filter) {
@@ -175,11 +179,6 @@ function aggregator({ beginTimestamp, endTimestamp, filterExpression, aggregatio
175
179
  return;
176
180
  }
177
181
  }
178
- const aggregateKeyLeaf = getTrieLeaf(aggregationTrieRoot, transaction, aggregationGranularity);
179
- if (!aggregateKeyLeaf.aggregateKey) {
180
- aggregateKeyLeaf.aggregateKey = aggregationEvaluator(transaction);
181
- }
182
- const aggregateKey = aggregateKeyLeaf.aggregateKey;
183
182
  // Prepare joined values for derived fields
184
183
  if (transaction.type == types_1.transactionTypeE.SALE) {
185
184
  const sku = globalRelations['sku'][transaction.ean];
@@ -194,8 +193,16 @@ function aggregator({ beginTimestamp, endTimestamp, filterExpression, aggregatio
194
193
  v[AMOUNT_SOLD_MAX] = (0, index_1.round2)((((sku === null || sku === void 0 ? void 0 : sku.price) || 0) / ((100 + (transaction.vat || (sku === null || sku === void 0 ? void 0 : sku.vat) || 21)) / 100)) * v[QTY_SOLD]);
195
194
  v[AMOUNT_SOLD_DISCOUNT] = (0, index_1.round2)(v[AMOUNT_SOLD_MAX] - v[AMOUNT_SOLD_EXCL]);
196
195
  }
197
- if (totals)
196
+ if (totals || totalsOnly)
198
197
  addTransactionToAggregations(beginTimestamp, endTimestamp, '** TOTAL **', rawAggregations, transaction, maxRows);
198
+ // No detail/subtotal rows when there are no groupers
199
+ if (totalsOnly)
200
+ return;
201
+ const aggregateKeyLeaf = getTrieLeaf(aggregationTrieRoot, transaction, aggregationGranularity);
202
+ if (!aggregateKeyLeaf.aggregateKey) {
203
+ aggregateKeyLeaf.aggregateKey = aggregationEvaluator(transaction);
204
+ }
205
+ const aggregateKey = aggregateKeyLeaf.aggregateKey;
199
206
  // Single subtotals are subtotals for first grouper level
200
207
  // Example: for 4 groupers we have rows like
201
208
  // g0 g1 g2 g3 <- normal row with no subtotal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softwear/latestcollectioncore",
3
- "version": "1.0.198",
3
+ "version": "1.0.199",
4
4
  "description": "Core functions for LatestCollections applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -242,10 +242,14 @@ function aggregator({
242
242
  .filter((join) => filterExpression.includes(join[0] + '.'))
243
243
  .map((join) => join[1])
244
244
  }
245
- const aggregationEvaluator = buildAggregationEvaluator(aggregationExpression)
246
- const aggregationGranularity = Object.entries(globalJoinableTables)
247
- .filter((join) => aggregationExpression.includes(join[0] + '.'))
248
- .map((join) => join[1])
245
+ // Empty aggregation expression = no groupers → only the totals row
246
+ const totalsOnly = !aggregationExpression
247
+ const aggregationEvaluator = totalsOnly ? undefined : buildAggregationEvaluator(aggregationExpression)
248
+ const aggregationGranularity = totalsOnly
249
+ ? []
250
+ : Object.entries(globalJoinableTables)
251
+ .filter((join) => aggregationExpression.includes(join[0] + '.'))
252
+ .map((join) => join[1])
249
253
  const aggregationTrieRoot: AggregateKeyTrieNode = {}
250
254
 
251
255
  return function (transaction: TransactionI): void {
@@ -257,11 +261,6 @@ function aggregator({
257
261
  if (filterLeaf.filterResult === -1) return
258
262
  }
259
263
  }
260
- const aggregateKeyLeaf = getTrieLeaf<AggregateKeyTrieNode>(aggregationTrieRoot, transaction, aggregationGranularity)
261
- if (!aggregateKeyLeaf.aggregateKey) {
262
- aggregateKeyLeaf.aggregateKey = aggregationEvaluator(transaction) as string
263
- }
264
- const aggregateKey = aggregateKeyLeaf.aggregateKey as string
265
264
  // Prepare joined values for derived fields
266
265
  if (transaction.type == transactionTypeE.SALE) {
267
266
  const sku = globalRelations['sku'][transaction.ean]
@@ -276,7 +275,16 @@ function aggregator({
276
275
  v[AMOUNT_SOLD_DISCOUNT] = round2(v[AMOUNT_SOLD_MAX] - v[AMOUNT_SOLD_EXCL])
277
276
  }
278
277
 
279
- if (totals) addTransactionToAggregations(beginTimestamp, endTimestamp, '** TOTAL **', rawAggregations, transaction, maxRows)
278
+ if (totals || totalsOnly) addTransactionToAggregations(beginTimestamp, endTimestamp, '** TOTAL **', rawAggregations, transaction, maxRows)
279
+
280
+ // No detail/subtotal rows when there are no groupers
281
+ if (totalsOnly) return
282
+
283
+ const aggregateKeyLeaf = getTrieLeaf<AggregateKeyTrieNode>(aggregationTrieRoot, transaction, aggregationGranularity)
284
+ if (!aggregateKeyLeaf.aggregateKey) {
285
+ aggregateKeyLeaf.aggregateKey = aggregationEvaluator!(transaction) as string
286
+ }
287
+ const aggregateKey = aggregateKeyLeaf.aggregateKey as string
280
288
 
281
289
  // Single subtotals are subtotals for first grouper level
282
290
  // Example: for 4 groupers we have rows like
@@ -178,6 +178,29 @@ describe('articleStatus', () => {
178
178
  expect(result[2].vector[articleStatus.VALUE_AVG_STOCK]).toBe(84.15000000000002)
179
179
  })
180
180
 
181
+ it('should calculate only the totals row when no groupers are selected', () => {
182
+ const rawAggregations = {}
183
+ articleStatus.runQuery(
184
+ { beginTimeStamp: 1569316408000, endTimeStamp: 1569316409000 + msYear },
185
+ rawAggregations,
186
+ true,
187
+ TRANSACTIONS,
188
+ [],
189
+ SKUS,
190
+ {},
191
+ {},
192
+ false,
193
+ 'transaction.ean=="000558000143"',
194
+ false
195
+ )
196
+
197
+ expect(Object.keys(rawAggregations)).toEqual(['** TOTAL **'])
198
+ const vector = [].slice.call(rawAggregations['** TOTAL **'])
199
+ articleStatus.postAgg(vector, msYear)
200
+ expect(vector[articleStatus.QTY_STOCK]).toBe(18)
201
+ expect(vector[articleStatus.QTY_END_STOCK]).toBe(17)
202
+ })
203
+
181
204
  it('should calculate aggregations', () => {
182
205
  const rawAggregations = {}
183
206
  articleStatus.runQuery(