Implement upsert label flow and use-based mark gone handling
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
@@ -22,7 +22,6 @@ export async function login(store, credentials) {
|
||||
user: credentials.userLogin,
|
||||
application: TRYTON_APPLICATION,
|
||||
},
|
||||
includeKitchen: false,
|
||||
});
|
||||
|
||||
const applicationKey = extractKey(payload);
|
||||
@@ -66,7 +65,6 @@ export async function logout(store) {
|
||||
key: store.session.applicationKey,
|
||||
application: TRYTON_APPLICATION,
|
||||
},
|
||||
includeKitchen: false,
|
||||
skipAuthFailureHandler: true,
|
||||
});
|
||||
}
|
||||
|
||||
+9
-14
@@ -20,7 +20,7 @@ function isSameOriginBaseUrl(baseUrl) {
|
||||
}
|
||||
}
|
||||
|
||||
function buildPathname({ database, kitchenId, path, includeKitchen = true }) {
|
||||
function buildPathname({ database, path }) {
|
||||
const encodedDatabase = encodeURIComponent(database);
|
||||
const rawPath = String(path || '').replace(/^\/+/, '');
|
||||
const keepTrailingSlash = rawPath.endsWith('/');
|
||||
@@ -30,23 +30,17 @@ function buildPathname({ database, kitchenId, path, includeKitchen = true }) {
|
||||
.map((segment) => encodeURIComponent(segment));
|
||||
const segments = [encodedDatabase];
|
||||
|
||||
if (includeKitchen && kitchenId) {
|
||||
segments.push('kitchen', encodeURIComponent(String(kitchenId)));
|
||||
}
|
||||
|
||||
segments.push(...encodedPathSegments);
|
||||
|
||||
const pathname = `/${segments.join('/')}`;
|
||||
return keepTrailingSlash ? `${pathname}/` : pathname;
|
||||
}
|
||||
|
||||
function buildUrl({ baseUrl, database, kitchenId, path, query = {}, includeKitchen = true }) {
|
||||
function buildUrl({ baseUrl, database, path, query = {} }) {
|
||||
const cleanBaseUrl = normalizeBaseUrl(baseUrl);
|
||||
const pathname = buildPathname({
|
||||
database,
|
||||
kitchenId,
|
||||
path,
|
||||
includeKitchen,
|
||||
});
|
||||
const searchParams = new URLSearchParams();
|
||||
|
||||
@@ -191,6 +185,10 @@ function isKitchensPath(path) {
|
||||
return String(path || '').replace(/^\/+/, '').replace(/\/+$/, '') === API_PATHS.kitchens;
|
||||
}
|
||||
|
||||
function isKitchenApiPath(path) {
|
||||
return String(path || '').replace(/^\/+/, '').startsWith('kitchen/');
|
||||
}
|
||||
|
||||
function shouldInvalidateValidatedSession(store, path, options = {}) {
|
||||
if (options.skipAuthFailureHandler) {
|
||||
return false;
|
||||
@@ -202,15 +200,16 @@ function shouldInvalidateValidatedSession(store, path, options = {}) {
|
||||
|
||||
return (
|
||||
isKitchensPath(path) ||
|
||||
options.includeKitchen !== false ||
|
||||
isKitchenApiPath(path) ||
|
||||
path === API_PATHS.items ||
|
||||
path === API_PATHS.locations ||
|
||||
path === API_PATHS.changes ||
|
||||
String(path || '').startsWith(`${API_PATHS.items}/`)
|
||||
);
|
||||
}
|
||||
|
||||
export async function apiRequest(store, path, options = {}) {
|
||||
const { config, session, activeKitchen } = store;
|
||||
const { config, session } = store;
|
||||
|
||||
if (!config.database) {
|
||||
throw new Error('Database name is required.');
|
||||
@@ -220,10 +219,8 @@ export async function apiRequest(store, path, options = {}) {
|
||||
const url = buildUrl({
|
||||
baseUrl: config.baseUrl,
|
||||
database: config.database,
|
||||
kitchenId: activeKitchen?.id,
|
||||
path,
|
||||
query: options.query,
|
||||
includeKitchen: options.includeKitchen !== false,
|
||||
});
|
||||
const headers = new Headers(options.headers || {});
|
||||
headers.set('Accept', options.accept || 'application/json');
|
||||
@@ -304,9 +301,7 @@ export function buildKitchenApiUrl(store, path, query = {}) {
|
||||
return buildUrl({
|
||||
baseUrl: store.config.baseUrl,
|
||||
database: store.config.database,
|
||||
kitchenId: store.activeKitchen?.id,
|
||||
path,
|
||||
query,
|
||||
includeKitchen: true,
|
||||
});
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,9 +1,7 @@
|
||||
import { apiRequest, getPath } from './client.js';
|
||||
|
||||
export async function listKitchens(store) {
|
||||
const payload = await apiRequest(store, getPath('kitchens'), {
|
||||
includeKitchen: false,
|
||||
});
|
||||
const payload = await apiRequest(store, getPath('kitchens'));
|
||||
if (Array.isArray(payload)) {
|
||||
return payload;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ export async function previewLabel(store, body) {
|
||||
method: 'POST',
|
||||
body,
|
||||
accept: 'image/svg+xml, image/png, application/json',
|
||||
includeKitchen: false,
|
||||
query: { label: 1, preview: 1 },
|
||||
});
|
||||
|
||||
|
||||
@@ -42,9 +42,7 @@ export async function fetchLocations(store) {
|
||||
return cached.value;
|
||||
}
|
||||
|
||||
const payload = await apiRequest(store, getPath('locations'), {
|
||||
includeKitchen: false,
|
||||
});
|
||||
const payload = await apiRequest(store, getPath('locations'));
|
||||
const tree = Array.isArray(payload)
|
||||
? payload
|
||||
: payload?.data || payload?.locations || [];
|
||||
|
||||
+70
-12
@@ -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 : [],
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user