Add quote and order stores plus ledger hash_version.

Mirror delivery on manifest for quote/order with customer entityId (excluding Lieferanten/POS), and support entity.list role=customer for pickers.
This commit is contained in:
seb
2026-08-06 19:58:35 +02:00
parent ae549fd022
commit b095ab6199
12 changed files with 987 additions and 45 deletions

View File

@@ -170,7 +170,7 @@ const MENU = {
entity: {
label: 'entity',
items: [
{ value: 'entity.list', label: 'list', hint: 'googleAuthId, companyId, customergroupId? → rows' },
{ value: 'entity.list', label: 'list', hint: 'googleAuthId, companyId, customergroupId?|role=customer → rows' },
{ value: 'entity.getById', label: 'getById', hint: 'googleAuthId, companyId, id → row' },
{ value: 'entity.create', label: 'create', hint: 'googleAuthId, companyId, JSON → row' },
{ value: 'entity.update', label: 'update', hint: 'googleAuthId, companyId, id, JSON → row' },
@@ -250,6 +250,66 @@ const MENU = {
},
],
},
quote: {
label: 'quote',
items: [
{
value: 'quote.list',
label: 'list',
hint: 'googleAuthId, companyId → summaries',
},
{
value: 'quote.getById',
label: 'getById',
hint: 'googleAuthId, companyId, id → quote',
},
{
value: 'quote.create',
label: 'create',
hint: 'googleAuthId, companyId, JSON body → quote',
},
{
value: 'quote.update',
label: 'update',
hint: 'googleAuthId, companyId, id, JSON patch → quote',
},
{
value: 'quote.delete',
label: 'delete',
hint: 'googleAuthId, companyId, id',
},
],
},
order: {
label: 'order',
items: [
{
value: 'order.list',
label: 'list',
hint: 'googleAuthId, companyId → summaries',
},
{
value: 'order.getById',
label: 'getById',
hint: 'googleAuthId, companyId, id → order',
},
{
value: 'order.create',
label: 'create',
hint: 'googleAuthId, companyId, JSON body → order',
},
{
value: 'order.update',
label: 'update',
hint: 'googleAuthId, companyId, id, JSON patch → order',
},
{
value: 'order.delete',
label: 'delete',
hint: 'googleAuthId, companyId, id',
},
],
},
category: {
label: 'category',
items: [
@@ -784,19 +844,35 @@ async function runMethod(client, action) {
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
const groupRaw = await askText('customergroup id (empty = all)', {
const roleRaw = await askText('role (customer|empty)', {
placeholder: '',
validate: (v) =>
v?.trim() && !/^\d+$/.test(v.trim()) ? 'Integer or empty' : undefined,
validate: (v) => {
const t = v?.trim?.() ?? '';
if (!t || t === 'customer') return undefined;
return 'customer or empty';
},
});
if (groupRaw == null) return;
const customergroupId = groupRaw.trim()
? Number(groupRaw.trim())
: undefined;
if (roleRaw == null) return;
const role = roleRaw.trim() || undefined;
let customergroupId;
if (!role) {
const groupRaw = await askText('customergroup id (empty = all)', {
placeholder: '',
validate: (v) =>
v?.trim() && !/^\d+$/.test(v.trim())
? 'Integer or empty'
: undefined,
});
if (groupRaw == null) return;
customergroupId = groupRaw.trim()
? Number(groupRaw.trim())
: undefined;
}
return [
'result[]',
await client.entity.list(Number(googleAuthId), Number(companyId), {
customergroupId,
role,
}),
];
}
@@ -1237,6 +1313,210 @@ async function runMethod(client, action) {
);
return ['ok', true];
}
case 'quote.list': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
return [
'result[]',
await client.quote.list(Number(googleAuthId), Number(companyId)),
];
}
case 'quote.getById': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
const id = await askInt('quote id');
if (id == null) return;
return [
'result',
await client.quote.getById(
Number(googleAuthId),
Number(companyId),
Number(id),
),
];
}
case 'quote.create': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
const bodyJson = await askText('quote JSON', {
placeholder:
'{"number":"A-2026-001","date":"2026-09-01","entityId":12,"lines":[{"sku":"1","amount":10,"net":99.5,"tax":19}]}',
validate: (v) => {
if (!v?.trim()) return 'Required';
try {
const parsed = JSON.parse(v);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
return 'Must be a JSON object';
}
} catch {
return 'Invalid JSON';
}
},
});
if (bodyJson == null) return;
return [
'result',
await client.quote.create(
Number(googleAuthId),
Number(companyId),
JSON.parse(bodyJson),
),
];
}
case 'quote.update': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
const id = await askInt('quote id');
if (id == null) return;
const patchJson = await askText('patch JSON', {
placeholder: '{"number":"A-2026-002","lines":[]}',
validate: (v) => {
if (!v?.trim()) return 'Required';
try {
const parsed = JSON.parse(v);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
return 'Must be a JSON object';
}
} catch {
return 'Invalid JSON';
}
},
});
if (patchJson == null) return;
return [
'result',
await client.quote.update(
Number(googleAuthId),
Number(companyId),
Number(id),
JSON.parse(patchJson),
),
];
}
case 'quote.delete': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
const id = await askInt('quote id');
if (id == null) return;
await client.quote.delete(
Number(googleAuthId),
Number(companyId),
Number(id),
);
return ['ok', true];
}
case 'order.list': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
return [
'result[]',
await client.order.list(Number(googleAuthId), Number(companyId)),
];
}
case 'order.getById': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
const id = await askInt('order id');
if (id == null) return;
return [
'result',
await client.order.getById(
Number(googleAuthId),
Number(companyId),
Number(id),
),
];
}
case 'order.create': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
const bodyJson = await askText('order JSON', {
placeholder:
'{"number":"B-2026-001","date":"2026-09-15","entityId":12,"lines":[{"sku":"1","amount":10,"net":99.5,"tax":19}]}',
validate: (v) => {
if (!v?.trim()) return 'Required';
try {
const parsed = JSON.parse(v);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
return 'Must be a JSON object';
}
} catch {
return 'Invalid JSON';
}
},
});
if (bodyJson == null) return;
return [
'result',
await client.order.create(
Number(googleAuthId),
Number(companyId),
JSON.parse(bodyJson),
),
];
}
case 'order.update': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
const id = await askInt('order id');
if (id == null) return;
const patchJson = await askText('patch JSON', {
placeholder: '{"number":"B-2026-002","lines":[]}',
validate: (v) => {
if (!v?.trim()) return 'Required';
try {
const parsed = JSON.parse(v);
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
return 'Must be a JSON object';
}
} catch {
return 'Invalid JSON';
}
},
});
if (patchJson == null) return;
return [
'result',
await client.order.update(
Number(googleAuthId),
Number(companyId),
Number(id),
JSON.parse(patchJson),
),
];
}
case 'order.delete': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const companyId = await askInt('company id');
if (companyId == null) return;
const id = await askInt('order id');
if (id == null) return;
await client.order.delete(
Number(googleAuthId),
Number(companyId),
Number(id),
);
return ['ok', true];
}
case 'lang.create': {
const iso639 = await askText('ISO 639', {
placeholder: 'de',