Files
lonc/src/api/stock.js
T

278 lines
7.4 KiB
JavaScript
Raw Normal View History

import { apiRequest, getPath } from './client.js';
const DEFAULT_LIST_PAGE_LIMIT = 100;
function unwrapEntryPayload(payload) {
return payload?.data || payload?.entry || payload?.item || payload;
}
function unwrapListPayload(payload) {
if (Array.isArray(payload)) {
return payload;
}
return payload?.data || payload?.entries || payload?.items || payload?.groups || [];
}
function hasExplicitPagination(filters = {}) {
return (
(filters.limit !== undefined && filters.limit !== null)
|| (filters.offset !== undefined && filters.offset !== null)
);
}
async function fetchAllListPages(store, path, baseQuery = {}) {
const items = [];
let offset = 0;
while (true) {
const payload = await apiRequest(store, path, {
query: {
...baseQuery,
limit: DEFAULT_LIST_PAGE_LIMIT,
offset,
},
});
const pageItems = unwrapListPayload(payload);
items.push(...pageItems);
if (pageItems.length < DEFAULT_LIST_PAGE_LIMIT) {
break;
}
offset += DEFAULT_LIST_PAGE_LIMIT;
}
return items;
}
export async function searchItemDefinitions(store, query) {
if (query.trim().length <= 2) {
return [];
}
const payload = await apiRequest(store, `${getPath('items')}/grouped`, {
query: { search_name: query, expanded: 0 },
});
if (Array.isArray(payload)) {
return payload;
}
return payload?.data || payload?.items || [];
}
export async function listStockEntries(store, filters = {}) {
const baseQuery = {};
const searchName = filters.searchName || filters.search_name;
if (searchName) {
baseQuery.search_name = searchName;
}
if (hasExplicitPagination(filters)) {
const query = { ...baseQuery };
if (filters.limit !== undefined && filters.limit !== null) {
query.limit = filters.limit;
}
if (filters.offset !== undefined && filters.offset !== null) {
query.offset = filters.offset;
}
const payload = await apiRequest(store, getPath('items'), {
query,
});
return unwrapListPayload(payload);
}
return fetchAllListPages(store, getPath('items'), baseQuery);
}
export async function listGroupedStockEntries(store, options = {}) {
const baseQuery = {};
const expanded = options.expanded ?? 1;
baseQuery.expanded = expanded;
const searchName = options.searchName || options.search_name;
if (searchName) {
baseQuery.search_name = searchName;
}
if (hasExplicitPagination(options)) {
const query = { ...baseQuery };
if (options.limit !== undefined && options.limit !== null) {
query.limit = options.limit;
}
if (options.offset !== undefined && options.offset !== null) {
query.offset = options.offset;
}
const payload = await apiRequest(store, `${getPath('items')}/grouped`, {
query,
});
return unwrapListPayload(payload);
}
return fetchAllListPages(store, `${getPath('items')}/grouped`, baseQuery);
}
export async function getStockEntry(store, stockId) {
const payload = await apiRequest(store, `${getPath('items')}/${stockId}`);
return unwrapEntryPayload(payload);
}
export async function createStockEntry(store, body) {
const payload = await apiRequest(store, getPath('items'), {
method: 'POST',
body,
query: { label: 1, print: 1 },
});
return unwrapEntryPayload(payload);
}
function normalizeUpsertResponse(payload) {
return {
status: payload?.status || null,
mode: payload?.mode || null,
operation: payload?.operation || null,
matchType: payload?.match_type || null,
matchedItem: payload?.matched_item || null,
item: payload?.item || null,
payload: payload?.payload || null,
};
}
function normalizeIdentifierLookupResponse(payload) {
return {
status: payload?.status || null,
source: payload?.source || null,
cacheHit: Boolean(payload?.cache_hit),
identifierCode: payload?.identifier_code || null,
identifierType: payload?.identifier_type || null,
item: payload?.item || null,
payloadFetchedAt: payload?.payload_fetched_at || null,
retryAfterSeconds:
Number.isInteger(payload?.retry_after_seconds) ? payload.retry_after_seconds : null,
staleCache: Boolean(payload?.stale_cache),
};
}
function normalizeItemLookupResponse(payload) {
return {
status: payload?.status || null,
found: Boolean(payload?.found),
update: Boolean(payload?.update),
identifierCode: payload?.identifier_code || null,
identifierType: payload?.identifier_type || null,
preview: payload?.preview || null,
updatedFields: Array.isArray(payload?.updated_fields) ? payload.updated_fields : [],
offPayloadFetchedAt: payload?.off_payload_fetched_at || null,
retryAfterSeconds:
Number.isInteger(payload?.retry_after_seconds) ? payload.retry_after_seconds : null,
staleCache: Boolean(payload?.stale_cache),
item: payload?.item || null,
};
}
export async function previewItemUpsert(store, body) {
const payload = await apiRequest(store, `${getPath('items')}/upsert`, {
method: 'POST',
body,
query: { mode: 'preview' },
});
return normalizeUpsertResponse(payload);
}
export async function applyItemUpsert(store, body) {
const payload = await apiRequest(store, `${getPath('items')}/upsert`, {
method: 'POST',
body,
query: { mode: 'apply' },
});
return normalizeUpsertResponse(payload);
}
export async function lookupItemByIdentifier(store, identifierCode) {
const payload = await apiRequest(store, `${getPath('items')}/lookup`, {
method: 'POST',
body: {
identifier_code: String(identifierCode || '').trim(),
},
});
return normalizeIdentifierLookupResponse(payload);
}
export async function lookupItemDetails(store, uuidB64, { update = false } = {}) {
const payload = await apiRequest(store, `${getPath('items')}/${uuidB64}/lookup`, {
method: 'POST',
query: { update: update ? 1 : 0 },
});
return normalizeItemLookupResponse(payload);
}
export async function patchStockItem(store, uuidB64, body) {
const payload = await apiRequest(store, `${getPath('items')}/${uuidB64}`, {
method: 'PATCH',
body,
});
return unwrapEntryPayload(payload);
}
export async function updateStockItem(store, uuidB64, body) {
await apiRequest(store, `${getPath('items')}/${uuidB64}/stock`, {
method: 'POST',
body,
});
return getStockEntry(store, uuidB64);
}
export async function deleteStockItem(store, uuidB64) {
const payload = await apiRequest(store, `${getPath('items')}/${uuidB64}`, {
method: 'DELETE',
});
return unwrapEntryPayload(payload);
}
export async function useStockItem(store, uuidB64) {
try {
await apiRequest(store, `${getPath('items')}/${uuidB64}/use`, {
method: 'POST',
});
return { status: 'used' };
} catch (error) {
const status = error?.status || error?.cause?.status;
if (status === 409 || status === 404) {
return { status: 'already_gone' };
}
throw error;
}
}
export async function adjustStockEntry(store, stockId, body) {
await apiRequest(store, `${getPath('items')}/${stockId}/stock`, {
method: 'POST',
body,
});
return getStockEntry(store, stockId);
}
export async function listKitchenChanges(store, { since, limit = 10 } = {}) {
const payload = await apiRequest(store, getPath('changes'), {
query: {
since,
limit,
},
});
return {
since: payload?.since || null,
nextCursor: payload?.next_cursor || null,
changes: Array.isArray(payload?.changes) ? payload.changes : [],
};
}