Refactor stock API to replace numeric flags with boolean values, add getItemLabel endpoint, and update tests/documentation
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
+14
-1
@@ -42,7 +42,7 @@ export async function previewLabel(store, body) {
|
||||
method: 'POST',
|
||||
body,
|
||||
accept: 'image/svg+xml, image/png, application/json',
|
||||
query: { label: 1, preview: 1 },
|
||||
query: { label: true, preview: true },
|
||||
});
|
||||
|
||||
const image = normalizeLabelImagePayload(payload);
|
||||
@@ -53,6 +53,19 @@ export async function previewLabel(store, body) {
|
||||
throw new Error('Label preview response did not include an image.');
|
||||
}
|
||||
|
||||
export async function getItemLabel(store, uuidB64) {
|
||||
const payload = await apiRequest(store, `${getPath('items')}/${uuidB64}/label`, {
|
||||
method: 'GET',
|
||||
accept: 'image/png, application/json',
|
||||
});
|
||||
const image = normalizeLabelImagePayload(payload);
|
||||
if (image) {
|
||||
return image;
|
||||
}
|
||||
|
||||
throw new Error('Item label response did not include an image.');
|
||||
}
|
||||
|
||||
export async function printItemLabel(store, uuidB64) {
|
||||
return apiRequest(store, `${getPath('items')}/${uuidB64}/print-label`, {
|
||||
method: 'POST',
|
||||
|
||||
+43
-6
@@ -2,6 +2,35 @@ import { apiRequest, getPath } from './client.js';
|
||||
|
||||
const DEFAULT_LIST_PAGE_LIMIT = 100;
|
||||
|
||||
function toBooleanFlag(value, defaultValue = false) {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (typeof value === 'boolean') {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
return value !== 0;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (!normalized) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (['1', 'true', 'yes', 'y', 'on'].includes(normalized)) {
|
||||
return true;
|
||||
}
|
||||
if (['0', 'false', 'no', 'n', 'off'].includes(normalized)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return Boolean(value);
|
||||
}
|
||||
|
||||
function unwrapEntryPayload(payload) {
|
||||
return payload?.data || payload?.entry || payload?.item || payload;
|
||||
}
|
||||
@@ -52,7 +81,7 @@ export async function searchItemDefinitions(store, query) {
|
||||
}
|
||||
|
||||
const payload = await apiRequest(store, `${getPath('items')}/grouped`, {
|
||||
query: { search_name: query, expanded: 0 },
|
||||
query: { search_name: query, expanded: false },
|
||||
});
|
||||
|
||||
if (Array.isArray(payload)) {
|
||||
@@ -90,7 +119,7 @@ export async function listStockEntries(store, filters = {}) {
|
||||
|
||||
export async function listGroupedStockEntries(store, options = {}) {
|
||||
const baseQuery = {};
|
||||
const expanded = options.expanded ?? 1;
|
||||
const expanded = toBooleanFlag(options.expanded, true);
|
||||
baseQuery.expanded = expanded;
|
||||
const searchName = options.searchName || options.search_name;
|
||||
if (searchName) {
|
||||
@@ -119,7 +148,7 @@ export async function listGroupedStockEntries(store, options = {}) {
|
||||
export async function getStockEntry(store, stockId, { allowInactive = false } = {}) {
|
||||
const path = `${getPath('items')}/${stockId}`;
|
||||
const payload = allowInactive
|
||||
? await apiRequest(store, path, { query: { allow_inactive: 1 } })
|
||||
? await apiRequest(store, path, { query: { allow_inactive: true } })
|
||||
: await apiRequest(store, path);
|
||||
return unwrapEntryPayload(payload);
|
||||
}
|
||||
@@ -128,7 +157,7 @@ export async function createStockEntry(store, body) {
|
||||
const payload = await apiRequest(store, getPath('items'), {
|
||||
method: 'POST',
|
||||
body,
|
||||
query: { label: 1, print: 1 },
|
||||
query: { label: true, print: true },
|
||||
});
|
||||
return unwrapEntryPayload(payload);
|
||||
}
|
||||
@@ -211,7 +240,7 @@ export async function lookupItemByIdentifier(store, identifierCode) {
|
||||
export async function lookupItemDetails(store, uuidB64, { update = false } = {}) {
|
||||
const payload = await apiRequest(store, `${getPath('items')}/${uuidB64}/lookup`, {
|
||||
method: 'POST',
|
||||
query: { update: update ? 1 : 0 },
|
||||
query: { update: toBooleanFlag(update, false) },
|
||||
});
|
||||
|
||||
return normalizeItemLookupResponse(payload);
|
||||
@@ -246,7 +275,7 @@ export async function createStockEvent(store, uuidB64, body) {
|
||||
export async function listStockEvents(store, uuidB64, options = {}) {
|
||||
const query = {};
|
||||
if (options.allowInactive) {
|
||||
query.allow_inactive = 1;
|
||||
query.allow_inactive = true;
|
||||
}
|
||||
if (options.limit !== undefined && options.limit !== null) {
|
||||
query.limit = options.limit;
|
||||
@@ -269,6 +298,14 @@ export async function listStockEvents(store, uuidB64, options = {}) {
|
||||
|
||||
export async function markStockGone(store, uuidB64, reason = 'consumed') {
|
||||
try {
|
||||
if (reason === 'consumed') {
|
||||
const result = await useStockItem(store, uuidB64);
|
||||
if (result.status === 'already_gone') {
|
||||
return { status: 'already_gone', reason };
|
||||
}
|
||||
return { status: 'gone', reason };
|
||||
}
|
||||
|
||||
await createStockEvent(store, uuidB64, {
|
||||
level: 'gone',
|
||||
gone_reason: reason,
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
export const APP_NAME = 'Lonc';
|
||||
export const APP_VERSION = typeof __APP_VERSION__ !== 'undefined' ? __APP_VERSION__ : '0.2.5';
|
||||
export const APP_VERSION = typeof __APP_VERSION__ !== 'undefined' ? __APP_VERSION__ : '0.2.6';
|
||||
export const TRYTON_APPLICATION = 'kitchen';
|
||||
|
||||
export const CONNECTION_STATES = {
|
||||
|
||||
@@ -924,7 +924,7 @@ export function stockListPageData(store) {
|
||||
} else {
|
||||
initTasks.push(
|
||||
this.loadGroupedEntries({
|
||||
expanded: 0,
|
||||
expanded: false,
|
||||
resetVisible: !restoredContext,
|
||||
}),
|
||||
);
|
||||
@@ -1309,7 +1309,7 @@ export function stockListPageData(store) {
|
||||
|
||||
if (mode === 'grouped') {
|
||||
if (!this.groupedLoaded) {
|
||||
await this.loadGroupedEntries({ expanded: 0, resetVisible: true });
|
||||
await this.loadGroupedEntries({ expanded: false, resetVisible: true });
|
||||
}
|
||||
this.hydrateGroupedEntriesInBackground().catch(() => {});
|
||||
return;
|
||||
@@ -1325,7 +1325,7 @@ export function stockListPageData(store) {
|
||||
: this.itemsLoaded);
|
||||
|
||||
if (this.viewMode === 'grouped') {
|
||||
await this.loadGroupedEntries({ expanded: 0, background: useBackground });
|
||||
await this.loadGroupedEntries({ expanded: false, background: useBackground });
|
||||
this.hydrateGroupedEntriesInBackground({ force: true }).catch(() => {});
|
||||
return;
|
||||
}
|
||||
@@ -1417,7 +1417,7 @@ export function stockListPageData(store) {
|
||||
this.invalidateMemo();
|
||||
this.persistRuntimeCache();
|
||||
},
|
||||
async loadGroupedEntries({ expanded = 1, background = false, resetVisible = false } = {}) {
|
||||
async loadGroupedEntries({ expanded = true, background = false, resetVisible = false } = {}) {
|
||||
if (!store.isConnected) {
|
||||
return;
|
||||
}
|
||||
@@ -1432,7 +1432,7 @@ export function stockListPageData(store) {
|
||||
|
||||
try {
|
||||
const loadedGroups = await listGroupedStockEntries(store, { expanded });
|
||||
if (expanded === 0) {
|
||||
if (!expanded) {
|
||||
this.applyGroupedSummary(loadedGroups, { resetVisible });
|
||||
return;
|
||||
}
|
||||
@@ -1461,7 +1461,7 @@ export function stockListPageData(store) {
|
||||
|
||||
this.groupedHydrating = true;
|
||||
try {
|
||||
await this.loadGroupedEntries({ expanded: 1, background: true });
|
||||
await this.loadGroupedEntries({ expanded: true, background: true });
|
||||
} finally {
|
||||
this.groupedHydrating = false;
|
||||
}
|
||||
@@ -1473,7 +1473,7 @@ export function stockListPageData(store) {
|
||||
}
|
||||
if (this.groupedLoaded) {
|
||||
tasks.push(
|
||||
this.loadGroupedEntries({ expanded: 0, background: true }).then(() =>
|
||||
this.loadGroupedEntries({ expanded: false, background: true }).then(() =>
|
||||
this.hydrateGroupedEntriesInBackground({ force: true }),
|
||||
),
|
||||
);
|
||||
@@ -2269,7 +2269,7 @@ export function stockListPageData(store) {
|
||||
? `${item.name} was already out of stock and removed from the group.`
|
||||
: `${item.name} was ${actionLabel} and removed from the group.`,
|
||||
});
|
||||
this.loadGroupedEntries({ expanded: 0, background: true }).catch(() => {});
|
||||
this.loadGroupedEntries({ expanded: false, background: true }).catch(() => {});
|
||||
} catch (error) {
|
||||
this.editErrors[item.id] = error.message || 'Removal failed.';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user