hedera-web/back/common/models/item.js

292 lines
8.1 KiB
JavaScript

const warehouseIds = [1, 44];
module.exports = Self => {
Self.remoteMethod('catalog', {
description: 'Get the catalog',
accessType: 'READ',
accepts: [
{
arg: 'dated',
type: 'Date',
description: 'The available date'
}, {
arg: 'typeFk',
type: 'Number',
description: 'The item type id'
}, {
arg: 'search',
type: 'String',
description: 'The search string'
}, {
arg: 'order',
type: 'String',
description: 'The order string'
}, {
arg: 'limit',
type: 'Number',
description: 'The maximum number of registers'
}, {
arg: 'tagFilter',
type: ['Object'],
description: 'The tag filter object'
}
],
returns: {
type: ['Object'],
description: 'The item list',
root: true,
},
http: {
path: `/catalog`,
verb: 'GET'
}
});
Self.catalog = async (dated, typeFk, search, order, limit, tagFilter) => {
let $ = Self.app.models;
let itemIds;
let inboundWhere = {
warehouseFk: {inq: warehouseIds},
available: {gt: 0},
dated: {lte: dated},
and: [
{or: [
{expired: {gt: dated}},
{expired: null}
]}
]
};
// Applies base filters
if (/^[0-9]+$/.test(search)) {
itemIds = [parseInt(search)];
} else {
if (typeFk || search) {
let where = {};
if (typeFk)
where.typeFk = typeFk;
if (search)
where.longName = {like: `%${search}%`};
let filter = {
fields: ['id'],
where
};
let items = await Self.find(filter);
itemIds = items.map(i => i.id);
}
let where = Object.assign({}, inboundWhere);
if (itemIds) where.itemFk = {inq: itemIds};
let inbounds = await $.Inbound.find({
fields: ['itemFk'],
where
});
itemIds = toValues(inbounds, 'itemFk');
}
// Applies tag filters
let baseItemIds = itemIds;
let tagItems = [];
let tagFilterIds = [];
if (tagFilter && tagFilter.length) {
for (let filter of tagFilter) {
let cond;
let values = filter.values;
if (values.length)
cond = {value: {inq: values}};
else if (values.min && values.max)
cond = {intValue: {between: [values.min, values.max]}};
else if (values.min)
cond = {intValue: {gte: values.min}};
else if (values.max)
cond = {intValue: {lte: values.max}};
let where = {
itemFk: {inq: itemIds},
tagFk: filter.tagFk
};
Object.assign(where, cond);
let itemTags = await $.ItemTag.find({
fields: ['itemFk'],
where
});
tagItems.push(toSet(itemTags, 'itemFk'));
tagFilterIds.push(filter.tagFk);
}
itemIds = intersect(tagItems);
}
// Obtains distinct tags and it's distinct values
let tagValues = await $.ItemTag.find({
fields: ['tagFk', 'value', 'intValue', 'priority'],
where: {
itemFk: {inq: itemIds},
tagFk: {nin: tagFilterIds}
},
order: 'tagFk, value'
});
let tagValueMap = toMultiMap(tagValues, 'tagFk');
for (let i = 0; i < tagItems.length; i++) {
let tagFk = tagFilter[i].tagFk;
let itemIds;
if (tagItems.length > 1) {
let siblings = tagItems.filter(v => v != tagItems[i]);
itemIds = intersect(siblings);
} else
itemIds = baseItemIds;
let tagValues = await $.ItemTag.find({
fields: ['value', 'intValue', 'priority'],
where: {
itemFk: {inq: itemIds},
tagFk: tagFk
},
order: 'value'
});
tagValueMap.set(tagFk, tagValues);
}
let tagIds = [...tagValueMap.keys()];
let tags = await $.Tag.find({
fields: ['id', 'name', 'isQuantitative', 'unit'],
where: {
id: {inq: tagIds}
}
});
for (let tag of tags) {
let tagValues = tagValueMap.get(tag.id);
let filter = tagFilter && tagFilter.find(i => i.tagFk == tag.id);
filter = filter && filter.values;
let values = toSet(tagValues, 'value');
if (Array.isArray(filter))
values = new Set([...filter, ...values]);
if (tag.isQuantitative) {
let intValues = toValues(tagValues, 'intValue');
if (filter) {
if (filter.min) intValues.push(filter.min);
if (filter.max) intValues.push(filter.max);
}
let min = Math.min(...intValues);
let max = Math.max(...intValues);
let dif = max - min;
let digits = new String(dif).length;
let step = Math.pow(10, digits - 1);
if (digits > 1 && step * 5 > dif) step /= 10;
Object.assign(tag, {
step,
min: Math.floor(min / step) * step,
max: Math.ceil(max / step) * step
});
}
Object.assign(tag, {
values: [...values],
filter
});
}
// Obtains items data
/*
let inbounds = await $.Inbound.find({
fields: ['itemFk', 'available', 'dated'],
include: 'item',
where: Object.assign(
{itemFk: {inq: itemIds}},
inboundWhere
)
});
*/
let items = await Self.find({
where: {id: {inq: itemIds}},
include: [
{
relation: 'tags',
scope: {include: 'tag'}
}, {
relation: 'inbounds',
scope: {
fields: ['available', 'dated'],
where: inboundWhere
}
}
],
limit: limit,
order: order
});
return {items, tags};
};
function toMap(objects, key) {
let map = new Map();
for (let object of objects)
map.set(object[key], object);
return map;
}
function toMultiMap(objects, key) {
let map = new Map();
for (let object of objects) {
let value = map.get(object[key]);
if (!value) map.set(object[key], value = []);
value.push(object);
}
return map;
}
function toSet(objects, key) {
let set = new Set();
for (let object of objects)
set.add(object[key]);
return set;
}
function toValues(objects, key) {
return [...toSet(objects, key)];
}
function intersect(sets) {
if (!sets.length) return [];
let array = [];
let mySets = sets.slice(0);
let firstSet = mySets.shift();
for (let value of firstSet) {
let isOnAll = true;
for (let set of mySets)
if (!set.has(value)) {
isOnAll = false;
break;
}
if (isOnAll)
array.push(value);
}
return array;
}
};