Implement upsert label flow and use-based mark gone handling
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-04-10 15:43:39 +02:00
parent caa6ca6ce1
commit 1dc1bb4912
24 changed files with 948 additions and 76 deletions
+70 -12
View File
@@ -10,7 +10,6 @@ export async function searchItemDefinitions(store, query) {
}
const payload = await apiRequest(store, `${getPath('items')}/grouped`, {
includeKitchen: false,
query: { search_name: query, expanded: 0 },
});
@@ -22,9 +21,7 @@ export async function searchItemDefinitions(store, query) {
}
export async function listStockEntries(store, filters = {}) {
const payload = await apiRequest(store, getPath('items'), {
includeKitchen: false,
});
const payload = await apiRequest(store, getPath('items'));
if (Array.isArray(payload)) {
return payload;
@@ -35,7 +32,6 @@ export async function listStockEntries(store, filters = {}) {
export async function listGroupedStockEntries(store) {
const payload = await apiRequest(store, `${getPath('items')}/grouped`, {
includeKitchen: false,
query: { expanded: 1 },
});
@@ -47,9 +43,7 @@ export async function listGroupedStockEntries(store) {
}
export async function getStockEntry(store, stockId) {
const payload = await apiRequest(store, `${getPath('items')}/${stockId}`, {
includeKitchen: false,
});
const payload = await apiRequest(store, `${getPath('items')}/${stockId}`);
return unwrapEntryPayload(payload);
}
@@ -57,17 +51,47 @@ export async function createStockEntry(store, body) {
const payload = await apiRequest(store, getPath('items'), {
method: 'POST',
body,
includeKitchen: false,
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,
};
}
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 updateStockItem(store, uuidB64, body) {
const payload = await apiRequest(store, `${getPath('items')}/${uuidB64}/stock`, {
method: 'POST',
body,
includeKitchen: false,
});
return unwrapEntryPayload(payload);
}
@@ -75,16 +99,50 @@ export async function updateStockItem(store, uuidB64, body) {
export async function deleteStockItem(store, uuidB64) {
const payload = await apiRequest(store, `${getPath('items')}/${uuidB64}`, {
method: 'DELETE',
includeKitchen: false,
});
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) {
return { status: 'already_gone' };
}
if (status === 404 || status === 405) {
await deleteStockItem(store, uuidB64);
return { status: 'fallback_delete' };
}
throw error;
}
}
export async function adjustStockEntry(store, stockId, body) {
const payload = await apiRequest(store, `${getPath('items')}/${stockId}/stock`, {
method: 'POST',
body,
includeKitchen: false,
});
return unwrapEntryPayload(payload);
}
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 : [],
};
}