Add entity customer numbers and scope APIs via selected company.
Entity gets an optional unique-per-company number with allocate/peek/isNumberFree helpers. Company-scoped store methods no longer take companyId and resolve google_auth.selected_company instead.
This commit is contained in:
@@ -80,7 +80,7 @@ Returns articles for export, optionally scoped to a category, including category
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = listExport(pool);
|
const fn = listExport(pool);
|
||||||
const articles = await fn(42, 1, null);
|
const articles = await fn(42, null);
|
||||||
// => [{ id, sku, name, slug, unitSi, net, taxRate, eans, categoryBreadcrumbs, fullHashes, ... }]
|
// => [{ id, sku, name, slug, unitSi, net, taxRate, eans, categoryBreadcrumbs, fullHashes, ... }]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ Returns a lightweight search index of all articles for a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = listSearchIndex(pool);
|
const fn = listSearchIndex(pool);
|
||||||
const articles = await fn(42, 1);
|
const articles = await fn(42);
|
||||||
// => [{ id, sku, name, eans, categoryIds }]
|
// => [{ id, sku, name, eans, categoryIds }]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Deletes a brand for a company by its id.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = del(pool);
|
const fn = del(pool);
|
||||||
await fn(42, 1, 3);
|
await fn(42, 3);
|
||||||
```
|
```
|
||||||
|
|
||||||
## `brand.list`
|
## `brand.list`
|
||||||
@@ -21,7 +21,7 @@ Lists the brands of a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = list(pool);
|
const fn = list(pool);
|
||||||
const brands = await fn(42, 1);
|
const brands = await fn(42);
|
||||||
// => [{ id, name, gsprpinfo }]
|
// => [{ id, name, gsprpinfo }]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -33,6 +33,6 @@ Creates or updates a brand for a company, keyed by name.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = upsert(pool);
|
const fn = upsert(pool);
|
||||||
const brand = await fn(42, 1, { name: 'Coca-Cola', gsprpinfo: 'x' });
|
const brand = await fn(42, { name: 'Coca-Cola', gsprpinfo: 'x' });
|
||||||
// => { id, name, gsprpinfo }
|
// => { id, name, gsprpinfo }
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ Returns the full category tree for a company together with its articles and the
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = getTreeForCompany(pool);
|
const fn = getTreeForCompany(pool);
|
||||||
const tree = await fn(42, 1);
|
const tree = await fn(42);
|
||||||
// => { languageId, tree: [{ id, posterminalIds, ... }], articles: [...] }
|
// => { languageId, tree: [{ id, posterminalIds, ... }], articles: [...] }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Deletes a company setting by key.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = del(pool);
|
const fn = del(pool);
|
||||||
await fn(42, 1, 'theme');
|
await fn(42, 'theme');
|
||||||
```
|
```
|
||||||
|
|
||||||
## `companysetting.get`
|
## `companysetting.get`
|
||||||
@@ -21,7 +21,7 @@ Returns a single company setting by key.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = get(pool);
|
const fn = get(pool);
|
||||||
const setting = await fn(42, 1, 'theme');
|
const setting = await fn(42, 'theme');
|
||||||
// => { key, value, frontend }
|
// => { key, value, frontend }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ Lists the settings of a company, optionally only frontend-visible ones.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = list(pool);
|
const fn = list(pool);
|
||||||
const settings = await fn(42, 1, { frontendOnly: true });
|
const settings = await fn(42, { frontendOnly: true });
|
||||||
// => [{ key, value, frontend }]
|
// => [{ key, value, frontend }]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -45,6 +45,6 @@ Sets (upserts) a company setting by key.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = set(pool);
|
const fn = set(pool);
|
||||||
const setting = await fn(42, 1, { key: 'theme', value: 'dark', frontend: true });
|
const setting = await fn(42, { key: 'theme', value: 'dark', frontend: true });
|
||||||
// => { key, value, frontend }
|
// => { key, value, frontend }
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Creates a new customer group for a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = create(pool);
|
const fn = create(pool);
|
||||||
const group = await fn(42, 1, { name: 'Wholesale' });
|
const group = await fn(42, { name: 'Wholesale' });
|
||||||
// => { id, name, sort }
|
// => { id, name, sort }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ Deletes a customer group for a company by its id.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = del(pool);
|
const fn = del(pool);
|
||||||
await fn(42, 1, 5);
|
await fn(42, 5);
|
||||||
```
|
```
|
||||||
|
|
||||||
## `customergroup.list`
|
## `customergroup.list`
|
||||||
@@ -33,7 +33,7 @@ Lists the customer groups of a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = list(pool);
|
const fn = list(pool);
|
||||||
const groups = await fn(42, 1);
|
const groups = await fn(42);
|
||||||
// => [{ id, name, sort }]
|
// => [{ id, name, sort }]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ Reorders the customer groups of a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = order(pool);
|
const fn = order(pool);
|
||||||
const result = await fn(42, 1, { customergroupIds: [3, 1, 2] });
|
const result = await fn(42, { customergroupIds: [3, 1, 2] });
|
||||||
// => { customergroupIds: [3, 1, 2] }
|
// => { customergroupIds: [3, 1, 2] }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -57,6 +57,6 @@ Updates the name of a customer group for a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = update(pool);
|
const fn = update(pool);
|
||||||
const group = await fn(42, 1, 5, { name: 'Retail' });
|
const group = await fn(42, 5, { name: 'Retail' });
|
||||||
// => { id, name, sort }
|
// => { id, name, sort }
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Creates a new delivery for a company with its lines.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = create(pool);
|
const fn = create(pool);
|
||||||
const delivery = await fn(42, 1, { number: 'D-1', date: '2026-01-01', supplierId: 5, lines: [...] });
|
const delivery = await fn(42, { number: 'D-1', date: '2026-01-01', supplierId: 5, lines: [...] });
|
||||||
// => { id, number, type, entityId, date, lines: [...] }
|
// => { id, number, type, entityId, date, lines: [...] }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ Deletes a delivery by its id within a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = del(pool);
|
const fn = del(pool);
|
||||||
await fn(42, 1, 5);
|
await fn(42, 5);
|
||||||
```
|
```
|
||||||
|
|
||||||
## `delivery.getById`
|
## `delivery.getById`
|
||||||
@@ -33,7 +33,7 @@ Returns a single delivery by its id within a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = getById(pool);
|
const fn = getById(pool);
|
||||||
const delivery = await fn(42, 1, 5);
|
const delivery = await fn(42, 5);
|
||||||
// => { id, number, type, entityId, date, lines: [...] }
|
// => { id, number, type, entityId, date, lines: [...] }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ Lists the deliveries of a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = list(pool);
|
const fn = list(pool);
|
||||||
const deliveries = await fn(42, 1);
|
const deliveries = await fn(42);
|
||||||
// => [{ id, number, type, entityId, date }]
|
// => [{ id, number, type, entityId, date }]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -57,6 +57,6 @@ Updates a delivery's header and/or lines.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = update(pool);
|
const fn = update(pool);
|
||||||
const delivery = await fn(42, 1, 5, { number: 'D-2', lines: [...] });
|
const delivery = await fn(42, 5, { number: 'D-2', lines: [...] });
|
||||||
// => { id, number, type, entityId, date, lines: [...] }
|
// => { id, number, type, entityId, date, lines: [...] }
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ This document is auto-generated from the JSDoc comments in `src/store` by runnin
|
|||||||
|
|
||||||
*Source: `src/store/entity/create.js`*
|
*Source: `src/store/entity/create.js`*
|
||||||
|
|
||||||
Creates a new entity (customer) in a customer group, recording history.
|
Creates a new entity (customer) in a customer group, recording history. Optional `number`; if omitted, allocates via `getnextnumberwithprefixandpadding` (`type` `entity`).
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = create(pool);
|
const fn = create(pool);
|
||||||
const entity = await fn(42, 1, { customergroupId: 5, name: 'Doe', firstName: 'John' });
|
const entity = await fn(42, { customergroupId: 5, name: 'Doe', firstName: 'John' });
|
||||||
// => { id, customergroupId, firstName, name, createdAt, updatedAt }
|
// => { id, customergroupId, firstName, name, number, createdAt, updatedAt }
|
||||||
```
|
```
|
||||||
|
|
||||||
## `entity.delete`
|
## `entity.delete`
|
||||||
@@ -22,7 +22,7 @@ Deletes an entity by its id within a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = del(pool);
|
const fn = del(pool);
|
||||||
await fn(42, 1, 5);
|
await fn(42, 5);
|
||||||
```
|
```
|
||||||
|
|
||||||
## `entity.getById`
|
## `entity.getById`
|
||||||
@@ -33,8 +33,22 @@ Returns a single entity by its id within a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = getById(pool);
|
const fn = getById(pool);
|
||||||
const entity = await fn(42, 1, 5);
|
const entity = await fn(42, 5);
|
||||||
// => { id, customergroupId, firstName, name, createdAt, updatedAt }
|
// => { id, customergroupId, firstName, name, number, createdAt, updatedAt }
|
||||||
|
```
|
||||||
|
|
||||||
|
## `entity.isNumberFree`
|
||||||
|
|
||||||
|
*Source: `src/store/entity/isNumberFree.js`*
|
||||||
|
|
||||||
|
Returns whether a customer number is free within the company. Pass `excludeEntityId` when editing so the entity's own number counts as free.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const fn = isNumberFree(pool);
|
||||||
|
const free = await fn(42, 'C-100');
|
||||||
|
// => true
|
||||||
|
const freeOnEdit = await fn(42, 'C-100', { excludeEntityId: 5 });
|
||||||
|
// => true
|
||||||
```
|
```
|
||||||
|
|
||||||
## `entity.list`
|
## `entity.list`
|
||||||
@@ -45,18 +59,30 @@ Lists the entities (customers) of a company, optionally filtered by customer gro
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = list(pool);
|
const fn = list(pool);
|
||||||
const entities = await fn(42, 1, { customergroupId: 5 });
|
const entities = await fn(42, { customergroupId: 5 });
|
||||||
// => [{ id, customergroupId, firstName, name, createdAt, updatedAt }]
|
// => [{ id, customergroupId, firstName, name, number, createdAt, updatedAt }]
|
||||||
|
```
|
||||||
|
|
||||||
|
## `entity.peekNextNumber`
|
||||||
|
|
||||||
|
*Source: `src/store/entity/peekNextNumber.js`*
|
||||||
|
|
||||||
|
Returns the next customer number that would be allocated for the company (`numbers` type `entity`) without consuming it.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const fn = peekNextNumber(pool);
|
||||||
|
const number = await fn(42);
|
||||||
|
// => '1'
|
||||||
```
|
```
|
||||||
|
|
||||||
## `entity.update`
|
## `entity.update`
|
||||||
|
|
||||||
*Source: `src/store/entity/update.js`*
|
*Source: `src/store/entity/update.js`*
|
||||||
|
|
||||||
Updates the name and/or first name of an entity, recording history.
|
Updates name, first name, and/or customer number of an entity, recording history. Optional `number` sets the customer number explicitly (does not auto-allocate).
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = update(pool);
|
const fn = update(pool);
|
||||||
const entity = await fn(42, 1, 5, { name: 'Doe', firstName: 'Jane' });
|
const entity = await fn(42, 5, { name: 'Doe', firstName: 'Jane', number: 'C-42' });
|
||||||
// => { id, customergroupId, firstName, name, createdAt, updatedAt }
|
// => { id, customergroupId, firstName, name, number, createdAt, updatedAt }
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Creates a new address for an entity.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = create(pool);
|
const fn = create(pool);
|
||||||
const address = await fn(42, 1, 5, { addressType: 'billing', street: 'Main St', city: 'Berlin' });
|
const address = await fn(42, 5, { addressType: 'billing', street: 'Main St', city: 'Berlin' });
|
||||||
// => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }
|
// => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ Deletes an address of an entity.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = del(pool);
|
const fn = del(pool);
|
||||||
await fn(42, 1, 5, 9);
|
await fn(42, 5, 9);
|
||||||
```
|
```
|
||||||
|
|
||||||
## `entityaddress.list`
|
## `entityaddress.list`
|
||||||
@@ -33,7 +33,7 @@ Lists the addresses of an entity.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = list(pool);
|
const fn = list(pool);
|
||||||
const addresses = await fn(42, 1, 5);
|
const addresses = await fn(42, 5);
|
||||||
// => [{ id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }]
|
// => [{ id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -45,6 +45,6 @@ Updates an address of an entity.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = update(pool);
|
const fn = update(pool);
|
||||||
const address = await fn(42, 1, 5, 9, { city: 'Hamburg' });
|
const address = await fn(42, 5, 9, { city: 'Hamburg' });
|
||||||
// => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }
|
// => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Creates a new contact for an entity.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = create(pool);
|
const fn = create(pool);
|
||||||
const contact = await fn(42, 1, 5, { contactType: 'email', contact: 'a@b.c' });
|
const contact = await fn(42, 5, { contactType: 'email', contact: 'a@b.c' });
|
||||||
// => { id, entityId, contactType, contact, sort }
|
// => { id, entityId, contactType, contact, sort }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ Deletes a contact of an entity.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = del(pool);
|
const fn = del(pool);
|
||||||
await fn(42, 1, 5, 9);
|
await fn(42, 5, 9);
|
||||||
```
|
```
|
||||||
|
|
||||||
## `entitycontact.list`
|
## `entitycontact.list`
|
||||||
@@ -33,7 +33,7 @@ Lists the contacts of an entity.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = list(pool);
|
const fn = list(pool);
|
||||||
const contacts = await fn(42, 1, 5);
|
const contacts = await fn(42, 5);
|
||||||
// => [{ id, entityId, contactType, contact, sort }]
|
// => [{ id, entityId, contactType, contact, sort }]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -45,6 +45,6 @@ Updates a contact of an entity.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = update(pool);
|
const fn = update(pool);
|
||||||
const contact = await fn(42, 1, 5, 9, { contact: 'b@c.d' });
|
const contact = await fn(42, 5, 9, { contact: 'b@c.d' });
|
||||||
// => { id, entityId, contactType, contact, sort }
|
// => { id, entityId, contactType, contact, sort }
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Deletes a posterminal by its id within a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = del(pool);
|
const fn = del(pool);
|
||||||
await fn(42, 1, 5);
|
await fn(42, 5);
|
||||||
```
|
```
|
||||||
|
|
||||||
## `posterminal.list`
|
## `posterminal.list`
|
||||||
@@ -21,7 +21,7 @@ Lists the posterminals of a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = list(pool);
|
const fn = list(pool);
|
||||||
const terminals = await fn(42, 1);
|
const terminals = await fn(42);
|
||||||
// => [{ id, name, token, pairingpin }]
|
// => [{ id, name, token, pairingpin }]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ Removes a category assignment from a posterminal (turns it off).
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = setOff(pool);
|
const fn = setOff(pool);
|
||||||
const result = await fn(42, 1, 5, 9);
|
const result = await fn(42, 5, 9);
|
||||||
// => { id, categoryIds: [...] }
|
// => { id, categoryIds: [...] }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ Removes all category assignments from a posterminal.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = setOffAll(pool);
|
const fn = setOffAll(pool);
|
||||||
const result = await fn(42, 1, 5);
|
const result = await fn(42, 5);
|
||||||
// => { id, categoryIds: [] }
|
// => { id, categoryIds: [] }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ Assigns a category to a posterminal (turns it on for that category).
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = setOn(pool);
|
const fn = setOn(pool);
|
||||||
const result = await fn(42, 1, 5, 9);
|
const result = await fn(42, 5, 9);
|
||||||
// => { id, categoryIds: [9, ...] }
|
// => { id, categoryIds: [9, ...] }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ Assigns all categories of a company to a posterminal.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = setOnAll(pool);
|
const fn = setOnAll(pool);
|
||||||
const result = await fn(42, 1, 5);
|
const result = await fn(42, 5);
|
||||||
// => { id, categoryIds: [...] }
|
// => { id, categoryIds: [...] }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -81,6 +81,6 @@ Creates or updates a posterminal for a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = upsert(pool);
|
const fn = upsert(pool);
|
||||||
const terminal = await fn(42, 1, { name: 'Kasse 1', pairingpin: '1234', token: 'abc' });
|
const terminal = await fn(42, { name: 'Kasse 1', pairingpin: '1234', token: 'abc' });
|
||||||
// => { id, name, token, pairingpin }
|
// => { id, name, token, pairingpin }
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Creates a new supplier for a company, recording history.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = create(pool);
|
const fn = create(pool);
|
||||||
const supplier = await fn(42, 1, { name: 'Acme Supplies' });
|
const supplier = await fn(42, { name: 'Acme Supplies' });
|
||||||
// => { id, name, createdAt, updatedAt }
|
// => { id, name, createdAt, updatedAt }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ Deletes a supplier by its id within a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = del(pool);
|
const fn = del(pool);
|
||||||
await fn(42, 1, 5);
|
await fn(42, 5);
|
||||||
```
|
```
|
||||||
|
|
||||||
## `supplier.list`
|
## `supplier.list`
|
||||||
@@ -33,7 +33,7 @@ Lists the suppliers of a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = list(pool);
|
const fn = list(pool);
|
||||||
const suppliers = await fn(42, 1);
|
const suppliers = await fn(42);
|
||||||
// => [{ id, name, createdAt, updatedAt }]
|
// => [{ id, name, createdAt, updatedAt }]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -45,6 +45,6 @@ Updates the name of a supplier, recording history.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = update(pool);
|
const fn = update(pool);
|
||||||
const supplier = await fn(42, 1, 5, { name: 'Acme GmbH' });
|
const supplier = await fn(42, 5, { name: 'Acme GmbH' });
|
||||||
// => { id, name, createdAt, updatedAt }
|
// => { id, name, createdAt, updatedAt }
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Deletes a unit for a company by its SI code.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = del(pool);
|
const fn = del(pool);
|
||||||
await fn(42, 1, 'l');
|
await fn(42, 'l');
|
||||||
```
|
```
|
||||||
|
|
||||||
## `unit.list`
|
## `unit.list`
|
||||||
@@ -21,7 +21,7 @@ Lists the units available for a company.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = list(pool);
|
const fn = list(pool);
|
||||||
const units = await fn(42, 1);
|
const units = await fn(42);
|
||||||
// => [{ id, si, basesi, basesifactor, symbol, name }]
|
// => [{ id, si, basesi, basesifactor, symbol, name }]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -33,6 +33,6 @@ Creates or updates a unit for a company, keyed by its SI code.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const fn = upsert(pool);
|
const fn = upsert(pool);
|
||||||
const unit = await fn(42, 1, { si: 'l', basesi: 'm3', basesifactor: 0.001, symbol: 'L', name: 'Liter' });
|
const unit = await fn(42, { si: 'l', basesi: 'm3', basesifactor: 0.001, symbol: 'L', name: 'Liter' });
|
||||||
// => { id, si, basesi, basesifactor, symbol, name }
|
// => { id, si, basesi, basesifactor, symbol, name }
|
||||||
```
|
```
|
||||||
|
|||||||
293
README.md
293
README.md
@@ -16,6 +16,8 @@ SQL lives in `src/sql/<table>.js`. Schema DDL: `src/schema.js` / `import 'libdas
|
|||||||
|
|
||||||
ID fields in the JS API use camelCase `…Id` (DB columns stay snake_case). `googleAuthId` is always `google_auth.id` (the logged-in user), not `companyuser.id`.
|
ID fields in the JS API use camelCase `…Id` (DB columns stay snake_case). `googleAuthId` is always `google_auth.id` (the logged-in user), not `companyuser.id`.
|
||||||
|
|
||||||
|
Company-scoped methods take **no** `companyId` argument: they use `google_auth.selected_company` (set via `google_auth.setSelectedCompany`). Missing selection → `No company selected`. Exceptions that still take `companyId`: `setSelectedCompany`, `companyuser.add`, `company.delete`, and internal helpers.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Schema
|
## Schema
|
||||||
@@ -124,9 +126,9 @@ Backend mapping:
|
|||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId)` | `{ si, basesi, basesifactor, symbol, name }[]` |
|
| `list` | `(googleAuthId)` | `{ si, basesi, basesifactor, symbol, name }[]` |
|
||||||
| `upsert` | `(googleAuthId, companyId, { si, basesi, basesifactor, symbol, name })` | `{ si, basesi, basesifactor, symbol, name }` |
|
| `upsert` | `(googleAuthId, { si, basesi, basesifactor, symbol, name })` | `{ si, basesi, basesifactor, symbol, name }` |
|
||||||
| `delete` | `(googleAuthId, companyId, si)` | `void` |
|
| `delete` | `(googleAuthId, si)` | `void` |
|
||||||
|
|
||||||
Shape (überall):
|
Shape (überall):
|
||||||
|
|
||||||
@@ -138,82 +140,84 @@ Shape (überall):
|
|||||||
|
|
||||||
### `list`
|
### `list`
|
||||||
|
|
||||||
Auth via `resolveCompanyAccess` (like `getTreeForCompany`). Returns only units of that company. Errors: `Company not found`, `Not authorized`.
|
Auth via selected company (like `getTreeForCompany`). Returns only units of that company. Errors: `No company selected`, `Company not found`, `Not authorized`.
|
||||||
|
|
||||||
### `upsert`
|
### `upsert`
|
||||||
|
|
||||||
Match key `(companyId, si)`. Inserts `unit` + `unittext`, or updates `basesi` / `basesifactor` and upserts `unittext` for the company language. `basesifactor` must be finite and `> 0`. Errors: `Company not found`, `Not authorized`, `Invalid unit`.
|
Match key `(companyId, si)`. Inserts `unit` + `unittext`, or updates `basesi` / `basesifactor` and upserts `unittext` for the company language. `basesifactor` must be finite and `> 0`. Errors: `No company selected`, `Company not found`, `Not authorized`, `Invalid unit`.
|
||||||
|
|
||||||
Default article unit `pc` is ensured **per company** on article create (with `unittext` symbol/name `pc` / `Piece` for the company language).
|
Default article unit `pc` is ensured **per company** on article create (with `unittext` symbol/name `pc` / `Piece` for the company language).
|
||||||
|
|
||||||
### `delete`
|
### `delete`
|
||||||
|
|
||||||
Deletes the unit for `(companyId, si)`. Blocked by FK if any article still references it (`Unit in use`). Missing → `Unit not found`. Errors: `Company not found`, `Not authorized`, `Unit not found`, `Unit in use`.
|
Deletes the unit for `(companyId, si)`. Blocked by FK if any article still references it (`Unit in use`). Missing → `Unit not found`. Errors: `No company selected`, `Company not found`, `Not authorized`, `Unit not found`, `Unit in use`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `companysetting`
|
## `companysetting`
|
||||||
|
|
||||||
Company-scoped key/value settings. Auth via `resolveCompanyAccess`.
|
Company-scoped key/value settings. Auth via selected company (`google_auth.selected_company` + membership).
|
||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId, { frontendOnly? })` | `{ key, value, frontend }[]` |
|
| `list` | `(googleAuthId, { frontendOnly? })` | `{ key, value, frontend }[]` |
|
||||||
| `get` | `(googleAuthId, companyId, key, { frontendOnly? })` | `{ key, value, frontend } \| undefined` |
|
| `get` | `(googleAuthId, key, { frontendOnly? })` | `{ key, value, frontend } \| undefined` |
|
||||||
| `set` | `(googleAuthId, companyId, { key, value, frontend? })` | `{ key, value, frontend }` |
|
| `set` | `(googleAuthId, { key, value, frontend? })` | `{ key, value, frontend }` |
|
||||||
| `delete` | `(googleAuthId, companyId, key)` | `void` |
|
| `delete` | `(googleAuthId, key)` | `void` |
|
||||||
|
|
||||||
- `value` is always a string (`NVARCHAR(MAX)`).
|
- `value` is always a string (`NVARCHAR(MAX)`).
|
||||||
- `frontend: true` → readable by frontend routes (`frontendOnly: true`). Default on `set` is `false` (backend-only).
|
- `frontend: true` → readable by frontend routes (`frontendOnly: true`). Default on `set` is `false` (backend-only).
|
||||||
- With `frontendOnly: true`, backend-only keys are omitted / `get` returns `undefined` (no leak via error type beyond missing).
|
- With `frontendOnly: true`, backend-only keys are omitted / `get` returns `undefined` (no leak via error type beyond missing).
|
||||||
|
|
||||||
Errors: `Company not found`, `Not authorized`, `Invalid setting`, `Setting not found`.
|
Errors: `No company selected`, `Company not found`, `Not authorized`, `Invalid setting`, `Setting not found`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `brand`
|
## `brand`
|
||||||
|
|
||||||
Company-scoped brands. Auth via `resolveCompanyAccess`.
|
Company-scoped brands. Auth via selected company (`google_auth.selected_company` + membership).
|
||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId)` | `{ id, name, gsprpinfo }[]` |
|
| `list` | `(googleAuthId)` | `{ id, name, gsprpinfo }[]` |
|
||||||
| `upsert` | `(googleAuthId, companyId, { name, gsprpinfo? })` | `{ id, name, gsprpinfo }` |
|
| `upsert` | `(googleAuthId, { name, gsprpinfo? })` | `{ id, name, gsprpinfo }` |
|
||||||
| `delete` | `(googleAuthId, companyId, id)` | `void` |
|
| `delete` | `(googleAuthId, id)` | `void` |
|
||||||
|
|
||||||
`brand.company_id` **NOT NULL**, unique `(company_id, name)`. `upsert` matches by `(companyId, name)`. `delete` blocked by FK if any article references it (`Brand in use`). Errors: `Company not found`, `Not authorized`, `Invalid brand`, `Brand not found`, `Brand in use`.
|
`brand.company_id` **NOT NULL**, unique `(company_id, name)`. `upsert` matches by `(companyId, name)`. `delete` blocked by FK if any article references it (`Brand in use`). Errors: `No company selected`, `Company not found`, `Not authorized`, `Invalid brand`, `Brand not found`, `Brand in use`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `customergroup`
|
## `customergroup`
|
||||||
|
|
||||||
Company-scoped customer groups. Auth via `resolveCompanyAccess`.
|
Company-scoped customer groups. Auth via selected company (`google_auth.selected_company` + membership).
|
||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId)` | `{ id, name, sort }[]` |
|
| `list` | `(googleAuthId)` | `{ id, name, sort }[]` |
|
||||||
| `create` | `(googleAuthId, companyId, { name })` | `{ id, name, sort }` |
|
| `create` | `(googleAuthId, { name })` | `{ id, name, sort }` |
|
||||||
| `update` | `(googleAuthId, companyId, id, { name })` | `{ id, name, sort }` |
|
| `update` | `(googleAuthId, id, { name })` | `{ id, name, sort }` |
|
||||||
| `order` | `(googleAuthId, companyId, { customergroupIds })` | `{ customergroupIds }` |
|
| `order` | `(googleAuthId, { customergroupIds })` | `{ customergroupIds }` |
|
||||||
| `delete` | `(googleAuthId, companyId, id)` | `void` |
|
| `delete` | `(googleAuthId, id)` | `void` |
|
||||||
|
|
||||||
List ordered by `sort`, `name`, `id`. `create` appends with next `sort` (`0…n`). `order` sets `sort` to each id’s index `0…n-1`; `customergroupIds` must be exactly the company’s groups (same set, no dups) else `Invalid customer group order`. Implicit groups `POS` (company create) and `Lieferanten` (first supplier) cannot be renamed (`Name cannot be changed`). Creating a group with those reserved names → `Name not allowed`.
|
List ordered by `sort`, `name`, `id`. `create` appends with next `sort` (`0…n`). `order` sets `sort` to each id’s index `0…n-1`; `customergroupIds` must be exactly the company’s groups (same set, no dups) else `Invalid customer group order`. Implicit groups `POS` (company create) and `Lieferanten` (first supplier) cannot be renamed (`Name cannot be changed`). Creating a group with those reserved names → `Name not allowed`.
|
||||||
|
|
||||||
Empty name → `Name required`. Deleting the POS group (or any group still referenced with `NO ACTION`) → `Customer group in use`. Cascades entities when the group is deleted. Errors: `Company not found`, `Not authorized`, `Name required`, `Name not allowed`, `Name cannot be changed`, `Invalid customer group order`, `Customer group not found`, `Customer group in use`.
|
Empty name → `Name required`. Deleting the POS group (or any group still referenced with `NO ACTION`) → `Customer group in use`. Cascades entities when the group is deleted. Errors: `No company selected`, `Company not found`, `Not authorized`, `Name required`, `Name not allowed`, `Name cannot be changed`, `Invalid customer group order`, `Customer group not found`, `Customer group in use`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `entity`
|
## `entity`
|
||||||
|
|
||||||
Entities belong to a `customergroup` of the company. Auth via `resolveCompanyAccess`.
|
Entities belong to a `customergroup` of the selected company. Company scope comes from `google_auth.selected_company` (not a `companyId` argument).
|
||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId, { customergroupId?, role? })` | `Entity[]` |
|
| `list` | `(googleAuthId, { customergroupId?, role? })` | `Entity[]` |
|
||||||
| `getById` | `(googleAuthId, companyId, id)` | `Entity` |
|
| `getById` | `(googleAuthId, id)` | `Entity` |
|
||||||
| `create` | `(googleAuthId, companyId, { customergroupId, name, firstName? })` | `Entity` |
|
| `create` | `(googleAuthId, { customergroupId, name, firstName?, number? })` | `Entity` |
|
||||||
| `update` | `(googleAuthId, companyId, id, { name?, firstName? })` | `Entity` |
|
| `update` | `(googleAuthId, id, { name?, firstName?, number? })` | `Entity` |
|
||||||
| `delete` | `(googleAuthId, companyId, id)` | `void` |
|
| `delete` | `(googleAuthId, id)` | `void` |
|
||||||
|
| `peekNextNumber` | `(googleAuthId)` | `string` |
|
||||||
|
| `isNumberFree` | `(googleAuthId, number, { excludeEntityId? })` | `boolean` |
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type Entity = {
|
type Entity = {
|
||||||
@@ -221,6 +225,7 @@ type Entity = {
|
|||||||
customergroupId: number,
|
customergroupId: number,
|
||||||
firstName: string | null,
|
firstName: string | null,
|
||||||
name: string,
|
name: string,
|
||||||
|
number: string | null,
|
||||||
createdAt: Date,
|
createdAt: Date,
|
||||||
updatedAt: Date,
|
updatedAt: Date,
|
||||||
}
|
}
|
||||||
@@ -228,66 +233,68 @@ type Entity = {
|
|||||||
|
|
||||||
`list` optional filters: `customergroupId` (must belong to the company), or `role: 'customer'` (entities whose customergroup name is not `Lieferanten` and not `POS` — for quote/order pickers). `role` wins over `customergroupId` when both are set. Unknown `role` → `Invalid role`.
|
`list` optional filters: `customergroupId` (must belong to the company), or `role: 'customer'` (entities whose customergroup name is not `Lieferanten` and not `POS` — for quote/order pickers). `role` wins over `customergroupId` when both are set. Unknown `role` → `Invalid role`.
|
||||||
|
|
||||||
`create` / `update` write `entityhistory` (`Erstellt`, or name/firstName change lines). `customergroupId` must belong to the company. Errors: `Company not found`, `Not authorized`, `Name required`, `Customer group not found`, `Entity not found`, `Invalid role`.
|
`number` is optional on the row (e.g. suppliers leave it null). Non-null numbers are unique per company (via `customergroup`). `create` allocates via `getnextnumberwithprefixandpadding` (`type` `entity`) when `number` is omitted. `update` only changes `number` when the key is present (no auto-allocate). `peekNextNumber` returns what the next allocate would yield without consuming it (`peeknextnumberwithprefixandpadding`; ensures the `numbers` row exists). `isNumberFree` checks occupancy company-wide; use `excludeEntityId` on edit so the current entity’s number stays free. Empty `number` → `Number required`.
|
||||||
|
|
||||||
|
`create` / `update` write `entityhistory` (`Erstellt`, or name/firstName/number change lines). `customergroupId` must belong to the company. Errors: `No company selected`, `Company not found`, `Not authorized`, `Name required`, `Customer group not found`, `Entity not found`, `Invalid role`, `Number already in use`, `Number required`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `entityaddress`
|
## `entityaddress`
|
||||||
|
|
||||||
Addresses for an entity. Auth via company + entity ownership.
|
Addresses for an entity. Auth via selected company + entity ownership.
|
||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId, entityId)` | `EntityAddress[]` |
|
| `list` | `(googleAuthId, entityId)` | `EntityAddress[]` |
|
||||||
| `create` | `(googleAuthId, companyId, entityId, { addressType, firstName?, name?, street?, streetNumber?, zip?, city?, county?, sort? })` | `EntityAddress` |
|
| `create` | `(googleAuthId, entityId, { addressType, firstName?, name?, street?, streetNumber?, zip?, city?, county?, sort? })` | `EntityAddress` |
|
||||||
| `update` | `(googleAuthId, companyId, entityId, id, patch)` | `EntityAddress` |
|
| `update` | `(googleAuthId, entityId, id, patch)` | `EntityAddress` |
|
||||||
| `delete` | `(googleAuthId, companyId, entityId, id)` | `void` |
|
| `delete` | `(googleAuthId, entityId, id)` | `void` |
|
||||||
|
|
||||||
`addressType` required. `sort` defaults to next index for the entity (`0…n`). List ordered by `sort`, `id`. Errors: `Company not found`, `Not authorized`, `Entity not found`, `Address type required`, `Address not found`, `Invalid sort`.
|
`addressType` required. `sort` defaults to next index for the entity (`0…n`). List ordered by `sort`, `id`. Errors: `No company selected`, `Company not found`, `Not authorized`, `Entity not found`, `Address type required`, `Address not found`, `Invalid sort`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `entitycontact`
|
## `entitycontact`
|
||||||
|
|
||||||
Contacts for an entity (`contactType` e.g. `email`, `phone`). Auth via company + entity ownership.
|
Contacts for an entity (`contactType` e.g. `email`, `phone`). Auth via selected company + entity ownership.
|
||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId, entityId)` | `{ id, entityId, contactType, contact, sort }[]` |
|
| `list` | `(googleAuthId, entityId)` | `{ id, entityId, contactType, contact, sort }[]` |
|
||||||
| `create` | `(googleAuthId, companyId, entityId, { contactType, contact, sort? })` | row |
|
| `create` | `(googleAuthId, entityId, { contactType, contact, sort? })` | row |
|
||||||
| `update` | `(googleAuthId, companyId, entityId, id, { contactType?, contact?, sort? })` | row |
|
| `update` | `(googleAuthId, entityId, id, { contactType?, contact?, sort? })` | row |
|
||||||
| `delete` | `(googleAuthId, companyId, entityId, id)` | `void` |
|
| `delete` | `(googleAuthId, entityId, id)` | `void` |
|
||||||
|
|
||||||
`sort` defaults to next index for the entity. List ordered by `sort`, `id`. Errors: `Company not found`, `Not authorized`, `Entity not found`, `Contact required`, `Contact not found`, `Invalid sort`.
|
`sort` defaults to next index for the entity. List ordered by `sort`, `id`. Errors: `No company selected`, `Company not found`, `Not authorized`, `Entity not found`, `Contact required`, `Contact not found`, `Invalid sort`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `supplier`
|
## `supplier`
|
||||||
|
|
||||||
Suppliers are `entity` rows in the company `customergroup` named `Lieferanten` (created implicitly on first supplier). Auth via `resolveCompanyAccess`.
|
Suppliers are `entity` rows in the company `customergroup` named `Lieferanten` (created implicitly on first supplier). Auth via selected company (`google_auth.selected_company` + membership).
|
||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId)` | `{ id, name, createdAt, updatedAt }[]` |
|
| `list` | `(googleAuthId)` | `{ id, name, createdAt, updatedAt }[]` |
|
||||||
| `create` | `(googleAuthId, companyId, { name })` | `{ id, name, createdAt, updatedAt }` |
|
| `create` | `(googleAuthId, { name })` | `{ id, name, createdAt, updatedAt }` |
|
||||||
| `update` | `(googleAuthId, companyId, id, { name })` | `{ id, name, createdAt, updatedAt }` |
|
| `update` | `(googleAuthId, id, { name })` | `{ id, name, createdAt, updatedAt }` |
|
||||||
| `delete` | `(googleAuthId, companyId, id)` | `void` |
|
| `delete` | `(googleAuthId, id)` | `void` |
|
||||||
|
|
||||||
`create` ensures `customergroup` `Lieferanten` for the company, inserts `entity` (`name` only; `first_name` null), writes `entityhistory` (`Erstellt`) with the auth `companyuser_id`. `update` renames and writes `Name geändert von "…" auf "…"` when the name actually changes; bumps `updated_at`. Empty name → `Name required`. `delete` removes the entity (`entityhistory` cascades; `manifest.entity_id` set null). Errors: `Company not found`, `Not authorized`, `Name required`, `Supplier not found`.
|
`create` ensures `customergroup` `Lieferanten` for the company, inserts `entity` (`name` only; `first_name` null), writes `entityhistory` (`Erstellt`) with the auth `companyuser_id`. `update` renames and writes `Name geändert von "…" auf "…"` when the name actually changes; bumps `updated_at`. Empty name → `Name required`. `delete` removes the entity (`entityhistory` cascades; `manifest.entity_id` set null). Errors: `No company selected`, `Company not found`, `Not authorized`, `Name required`, `Supplier not found`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `delivery`
|
## `delivery`
|
||||||
|
|
||||||
Company-scoped goods receipts on `manifest` / `manifestarticle` with fixed `type = 'delivery'`. Auth via `resolveCompanyAccess`. `manifest.company_id` scopes the list (`ON DELETE NO ACTION` — avoid SQL Server multiple cascade paths with `entity_id`).
|
Company-scoped goods receipts on `manifest` / `manifestarticle` with fixed `type = 'delivery'`. Auth via selected company (`google_auth.selected_company` + membership). `manifest.company_id` scopes the list (`ON DELETE NO ACTION` — avoid SQL Server multiple cascade paths with `entity_id`).
|
||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId)` | `DeliverySummary[]` |
|
| `list` | `(googleAuthId)` | `DeliverySummary[]` |
|
||||||
| `getById` | `(googleAuthId, companyId, id)` | `Delivery` |
|
| `getById` | `(googleAuthId, id)` | `Delivery` |
|
||||||
| `create` | `(googleAuthId, companyId, { number, date, supplierId?, lines })` | `Delivery` |
|
| `create` | `(googleAuthId, { number, date, supplierId?, lines })` | `Delivery` |
|
||||||
| `update` | `(googleAuthId, companyId, id, { number?, date?, supplierId?, lines? })` | `Delivery` |
|
| `update` | `(googleAuthId, id, { number?, date?, supplierId?, lines? })` | `Delivery` |
|
||||||
| `delete` | `(googleAuthId, companyId, id)` | `void` |
|
| `delete` | `(googleAuthId, id)` | `void` |
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type DeliverySummary = {
|
type DeliverySummary = {
|
||||||
@@ -316,21 +323,21 @@ type Delivery = DeliverySummary & { lines: DeliveryLine[] }
|
|||||||
|
|
||||||
`update` patches header fields that are present. If `lines` is present, replace-all lines; if omitted, leave lines unchanged. Returns full `Delivery`.
|
`update` patches header fields that are present. If `lines` is present, replace-all lines; if omitted, leave lines unchanged. Returns full `Delivery`.
|
||||||
|
|
||||||
`delete` removes the manifest (`manifestarticle` cascades). Errors: `Company not found`, `Not authorized`, `Delivery not found`, `Supplier not found`, `Article not found`, `Invalid delivery`, `Invalid lines`.
|
`delete` removes the manifest (`manifestarticle` cascades). Errors: `No company selected`, `Company not found`, `Not authorized`, `Delivery not found`, `Supplier not found`, `Article not found`, `Invalid delivery`, `Invalid lines`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `quote`
|
## `quote`
|
||||||
|
|
||||||
Company-scoped quotes on `manifest` / `manifestarticle` with fixed `type = 'quote'`. Auth via `resolveCompanyAccess`. Same line shape as `delivery` (no `transactedAmount` — ledger owns movements). `manifest.date` is the document date; HTTP/OpenAPI may describe it as valid-until.
|
Company-scoped quotes on `manifest` / `manifestarticle` with fixed `type = 'quote'`. Auth via selected company (`google_auth.selected_company` + membership). Same line shape as `delivery` (no `transactedAmount` — ledger owns movements). `manifest.date` is the document date; HTTP/OpenAPI may describe it as valid-until.
|
||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId)` | `QuoteSummary[]` |
|
| `list` | `(googleAuthId)` | `QuoteSummary[]` |
|
||||||
| `getById` | `(googleAuthId, companyId, id)` | `Quote` |
|
| `getById` | `(googleAuthId, id)` | `Quote` |
|
||||||
| `create` | `(googleAuthId, companyId, { number, date, entityId?, lines })` | `Quote` |
|
| `create` | `(googleAuthId, { number, date, entityId?, lines })` | `Quote` |
|
||||||
| `update` | `(googleAuthId, companyId, id, { number?, date?, entityId?, lines? })` | `Quote` |
|
| `update` | `(googleAuthId, id, { number?, date?, entityId?, lines? })` | `Quote` |
|
||||||
| `delete` | `(googleAuthId, companyId, id)` | `void` |
|
| `delete` | `(googleAuthId, id)` | `void` |
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type QuoteSummary = {
|
type QuoteSummary = {
|
||||||
@@ -357,7 +364,7 @@ type Quote = QuoteSummary & { lines: ManifestLine[] }
|
|||||||
|
|
||||||
`entityId` null or a company entity whose customergroup is not named `Lieferanten` or `POS` (else `Entity not found`). Lines: `sku` (category tree → `Article not found`), `amount`, `net`, `tax` (`tax.ensure`); `rebate` defaults `0`. Empty/invalid `number` or `date` → `Invalid quote`; bad lines → `Invalid lines`.
|
`entityId` null or a company entity whose customergroup is not named `Lieferanten` or `POS` (else `Entity not found`). Lines: `sku` (category tree → `Article not found`), `amount`, `net`, `tax` (`tax.ensure`); `rebate` defaults `0`. Empty/invalid `number` or `date` → `Invalid quote`; bad lines → `Invalid lines`.
|
||||||
|
|
||||||
`update`: present fields only; `lines` present → replace-all. `delete` cascades lines. Errors: `Company not found`, `Not authorized`, `Quote not found`, `Entity not found`, `Article not found`, `Invalid quote`, `Invalid lines`.
|
`update`: present fields only; `lines` present → replace-all. `delete` cascades lines. Errors: `No company selected`, `Company not found`, `Not authorized`, `Quote not found`, `Entity not found`, `Article not found`, `Invalid quote`, `Invalid lines`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -367,11 +374,11 @@ Company-scoped orders on `manifest` / `manifestarticle` with fixed `type = 'orde
|
|||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId)` | `OrderSummary[]` |
|
| `list` | `(googleAuthId)` | `OrderSummary[]` |
|
||||||
| `getById` | `(googleAuthId, companyId, id)` | `Order` |
|
| `getById` | `(googleAuthId, id)` | `Order` |
|
||||||
| `create` | `(googleAuthId, companyId, { number, date, entityId?, lines })` | `Order` |
|
| `create` | `(googleAuthId, { number, date, entityId?, lines })` | `Order` |
|
||||||
| `update` | `(googleAuthId, companyId, id, { number?, date?, entityId?, lines? })` | `Order` |
|
| `update` | `(googleAuthId, id, { number?, date?, entityId?, lines? })` | `Order` |
|
||||||
| `delete` | `(googleAuthId, companyId, id)` | `void` |
|
| `delete` | `(googleAuthId, id)` | `void` |
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type OrderSummary = {
|
type OrderSummary = {
|
||||||
@@ -385,7 +392,7 @@ type OrderSummary = {
|
|||||||
type Order = OrderSummary & { lines: ManifestLine[] } // ManifestLine as in quote
|
type Order = OrderSummary & { lines: ManifestLine[] } // ManifestLine as in quote
|
||||||
```
|
```
|
||||||
|
|
||||||
Errors: `Company not found`, `Not authorized`, `Order not found`, `Entity not found`, `Article not found`, `Invalid order`, `Invalid lines`.
|
Errors: `No company selected`, `Company not found`, `Not authorized`, `Order not found`, `Entity not found`, `Article not found`, `Invalid order`, `Invalid lines`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -409,28 +416,28 @@ Engine also maintains `ledger_start_transaction_id` / `ledger_start_sequence_num
|
|||||||
|
|
||||||
## `posterminal`
|
## `posterminal`
|
||||||
|
|
||||||
Company-scoped POS terminals. Auth via `resolveCompanyAccess`.
|
Company-scoped POS terminals. Auth via selected company (`google_auth.selected_company` + membership).
|
||||||
|
|
||||||
| Method | Signature | Returns |
|
| Method | Signature | Returns |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `list` | `(googleAuthId, companyId)` | `{ id, name, token, pairingpin }[]` |
|
| `list` | `(googleAuthId)` | `{ id, name, token, pairingpin }[]` |
|
||||||
| `upsert` | `(googleAuthId, companyId, { id?, name, token?, pairingpin })` | `{ id, name, token, pairingpin }` |
|
| `upsert` | `(googleAuthId, { id?, name, token?, pairingpin })` | `{ id, name, token, pairingpin }` |
|
||||||
| `delete` | `(googleAuthId, companyId, id)` | `void` |
|
| `delete` | `(googleAuthId, id)` | `void` |
|
||||||
| `setOn` | `(googleAuthId, companyId, posterminalId, categoryId)` | `{ id, categoryIds[] }` |
|
| `setOn` | `(googleAuthId, posterminalId, categoryId)` | `{ id, categoryIds[] }` |
|
||||||
| `setOff` | `(googleAuthId, companyId, posterminalId, categoryId)` | `{ id, categoryIds[] }` |
|
| `setOff` | `(googleAuthId, posterminalId, categoryId)` | `{ id, categoryIds[] }` |
|
||||||
| `setOnAll` | `(googleAuthId, companyId, posterminalId)` | `{ id, categoryIds[] }` |
|
| `setOnAll` | `(googleAuthId, posterminalId)` | `{ id, categoryIds[] }` |
|
||||||
| `setOffAll` | `(googleAuthId, companyId, posterminalId)` | `{ id, categoryIds[] }` |
|
| `setOffAll` | `(googleAuthId, posterminalId)` | `{ id, categoryIds[] }` |
|
||||||
| `getCategoryPosterminalIds` | `(companyId)` | `{ [categoryId]: posterminalId[] }` (internal, used by category tree) |
|
| `getCategoryPosterminalIds` | `(companyId)` | `{ [categoryId]: posterminalId[] }` (internal, used by category tree) |
|
||||||
|
|
||||||
`posterminal.company_id` **NOT NULL**. `name` is required. `token` is nullable and unique (pairing code assigned during setup). `pairingpin` is required.
|
`posterminal.company_id` **NOT NULL**. `name` is required. `token` is nullable and unique (pairing code assigned during setup). `pairingpin` is required.
|
||||||
|
|
||||||
`upsert`: if `id` is provided, updates the existing posterminal (must belong to company); otherwise creates a new one. Errors: `Company not found`, `Not authorized`, `Invalid posterminal`, `Posterminal not found`.
|
`upsert`: if `id` is provided, updates the existing posterminal (must belong to company); otherwise creates a new one. Errors: `No company selected`, `Company not found`, `Not authorized`, `Invalid posterminal`, `Posterminal not found`.
|
||||||
|
|
||||||
`setOn` / `setOff`: toggle a single category's visibility on a single terminal. `setOn` inserts the row (idempotent — no error if already present); `setOff` deletes it (idempotent). Both return the updated `categoryIds` for that terminal. Errors: `Company not found`, `Not authorized`, `Posterminal not found`, `Invalid posterminal or category`.
|
`setOn` / `setOff`: toggle a single category's visibility on a single terminal. `setOn` inserts the row (idempotent — no error if already present); `setOff` deletes it (idempotent). Both return the updated `categoryIds` for that terminal. Errors: `No company selected`, `Company not found`, `Not authorized`, `Posterminal not found`, `Invalid posterminal or category`.
|
||||||
|
|
||||||
`setOnAll` / `setOffAll`: toggle **all** company categories on a single terminal. `setOnAll` walks the company's category tree and inserts any missing links; `setOffAll` removes all category links for the terminal. Both return the updated `categoryIds` for that terminal. Errors: `Company not found`, `Not authorized`, `Posterminal not found`, `Invalid posterminal`.
|
`setOnAll` / `setOffAll`: toggle **all** company categories on a single terminal. `setOnAll` walks the company's category tree and inserts any missing links; `setOffAll` removes all category links for the terminal. Both return the updated `categoryIds` for that terminal. Errors: `No company selected`, `Company not found`, `Not authorized`, `Posterminal not found`, `Invalid posterminal`.
|
||||||
|
|
||||||
`delete` cascades to `posterminalcategory`. Errors: `Company not found`, `Not authorized`, `Posterminal not found`.
|
`delete` cascades to `posterminalcategory`. Errors: `No company selected`, `Company not found`, `Not authorized`, `Posterminal not found`.
|
||||||
|
|
||||||
### Category tree integration
|
### Category tree integration
|
||||||
|
|
||||||
@@ -447,7 +454,7 @@ Company-scoped POS terminals. Auth via `resolveCompanyAccess`.
|
|||||||
| `move` | `({ googleAuthId, id, parentId })` | `{ id, parentId, sort }` |
|
| `move` | `({ googleAuthId, id, parentId })` | `{ id, parentId, sort }` |
|
||||||
| `order` | `({ googleAuthId, parentId, categoryIds })` | `{ categoryIds }` |
|
| `order` | `({ googleAuthId, parentId, categoryIds })` | `{ categoryIds }` |
|
||||||
| `delete` | `({ googleAuthId, id })` | `void` — `Category has children` if child categories remain; FK `categoryarticle` also blocks deletion |
|
| `delete` | `({ googleAuthId, id })` | `void` — `Category has children` if child categories remain; FK `categoryarticle` also blocks deletion |
|
||||||
| `getTreeForCompany` | `(googleAuthId, companyId)` | `{ languageId, tree, articles }` — tree rows carry `name` + `slug` |
|
| `getTreeForCompany` | `(googleAuthId)` | `{ languageId, tree, articles }` — tree rows carry `name` + `slug` |
|
||||||
| `getCategoryArticles` | `(googleAuthId, categoryId)` | `{ id, sku, name, slug, net, taxRate, optionsCount, articleListCount, childCount, fatherArticleId, fatherSku, fullHash, thumbW, thumbH, thumbHash }[]` |
|
| `getCategoryArticles` | `(googleAuthId, categoryId)` | `{ id, sku, name, slug, net, taxRate, optionsCount, articleListCount, childCount, fatherArticleId, fatherSku, fullHash, thumbW, thumbH, thumbHash }[]` |
|
||||||
| `addImage` | `(googleAuthId, categoryId, imageBuffer)` | `{ id, thumbW, thumbH, thumbHash }` |
|
| `addImage` | `(googleAuthId, categoryId, imageBuffer)` | `{ id, thumbW, thumbH, thumbHash }` |
|
||||||
| `deleteImage` | `(googleAuthId, categoryId)` | `{ id, thumbW: null, thumbH: null, thumbHash: null }` |
|
| `deleteImage` | `(googleAuthId, categoryId)` | `{ id, thumbW: null, thumbH: null, thumbHash: null }` |
|
||||||
@@ -456,7 +463,7 @@ Company-scoped POS terminals. Auth via `resolveCompanyAccess`.
|
|||||||
|
|
||||||
1. `parentId` exists, else `Parent not found`
|
1. `parentId` exists, else `Parent not found`
|
||||||
2. Walk ancestors to root; find `company` with `root_category_id` = root
|
2. Walk ancestors to root; find `company` with `root_category_id` = root
|
||||||
3. `companyuser` for `(googleAuthId, companyId)`, else `Not authorized`
|
3. `companyuser` for selected company via `googleAuthId`, else `Not authorized`
|
||||||
4. Insert `category` (next sibling `sort`) + `categorytext` (`name`, slugified `slug`, company default language); returns `{ id, parentId, sort, name, slug }`
|
4. Insert `category` (next sibling `sort`) + `categorytext` (`name`, slugified `slug`, company default language); returns `{ id, parentId, sort, name, slug }`
|
||||||
|
|
||||||
`getTreeForCompany` throws `Not authorized` if `googleAuthId` is not a `companyuser` of `companyId`, and `Company not found` if the company is missing, has no `root_category_id`, or no `default_language_id`.
|
`getTreeForCompany` throws `Not authorized` if `googleAuthId` is not a `companyuser` of `companyId`, and `Company not found` if the company is missing, has no `root_category_id`, or no `default_language_id`.
|
||||||
@@ -519,7 +526,7 @@ Company-scoped POS terminals. Auth via `resolveCompanyAccess`.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`listSearchIndex` returns every article in the company (reachable via the category tree). Designed for client-side search / autocomplete preload. Auth via `resolveCompanyAccess`. Errors: `Company not found`, `Not authorized`.
|
`listSearchIndex` returns every article in the company (reachable via the category tree). Designed for client-side search / autocomplete preload. Auth via selected company (`google_auth.selected_company` + membership). Errors: `No company selected`, `Company not found`, `Not authorized`.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type SearchIndexEntry = {
|
type SearchIndexEntry = {
|
||||||
@@ -531,7 +538,7 @@ type SearchIndexEntry = {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`listExport` returns articles in a category subtree (root = company when `categoryId` omitted). `categoryId` must be reachable via the selected company's root category (else `Not authorized`). Auth via `resolveCompanyAccess` + `resolveCategoryAccess`. Errors: `Company not found`, `Parent not found`, `Not authorized`.
|
`listExport` returns articles in a category subtree (root = company when `categoryId` omitted). `categoryId` must be reachable via the selected company's root category (else `Not authorized`). Auth via selected company + `resolveCategoryAccess`. Errors: `No company selected`, `Company not found`, `Parent not found`, `Not authorized`.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type ArticleExportEntry = {
|
type ArticleExportEntry = {
|
||||||
@@ -662,8 +669,8 @@ res.set('Content-Type', thumb.contentType).send(thumb.buffer);
|
|||||||
| `PATCH /api/company/:id` | `company.update(id, { iso639, name, taxrate, reducedtaxrate })` |
|
| `PATCH /api/company/:id` | `company.update(id, { iso639, name, taxrate, reducedtaxrate })` |
|
||||||
| `DELETE /api/company/:id` | `company.delete(id)` |
|
| `DELETE /api/company/:id` | `company.delete(id)` |
|
||||||
| `PUT /api/auth/selected-company` | `google_auth.setSelectedCompany(googleAuthId, companyId)` |
|
| `PUT /api/auth/selected-company` | `google_auth.setSelectedCompany(googleAuthId, companyId)` |
|
||||||
| `GET /api/category/tree` | `category.getTreeForCompany(googleAuthId, companyId)` |
|
| `GET /api/category/tree` | `category.getTreeForCompany(googleAuthId)` |
|
||||||
| `GET /api/category/export.zip` | `category.getTreeForCompany(googleAuthId, companyId)` + `pic.getImageByHash` |
|
| `GET /api/category/export.zip` | `category.getTreeForCompany(googleAuthId)` + `pic.getImageByHash` |
|
||||||
| `POST /api/category` | `category.createUnderParent({ googleAuthId, parentId, name })` |
|
| `POST /api/category` | `category.createUnderParent({ googleAuthId, parentId, name })` |
|
||||||
| `PATCH /api/category/:id` | `category.rename({ googleAuthId, id, name })` |
|
| `PATCH /api/category/:id` | `category.rename({ googleAuthId, id, name })` |
|
||||||
| `PUT /api/category/order` | `category.order({ googleAuthId, parentId, categoryIds })` |
|
| `PUT /api/category/order` | `category.order({ googleAuthId, parentId, categoryIds })` |
|
||||||
@@ -671,64 +678,66 @@ res.set('Content-Type', thumb.contentType).send(thumb.buffer);
|
|||||||
| `DELETE /api/category/:id` | `category.delete({ googleAuthId, id })` |
|
| `DELETE /api/category/:id` | `category.delete({ googleAuthId, id })` |
|
||||||
| `POST /api/category/:id/image` | `category.addImage(googleAuthId, categoryId, imageBuffer)` |
|
| `POST /api/category/:id/image` | `category.addImage(googleAuthId, categoryId, imageBuffer)` |
|
||||||
| `DELETE /api/category/:id/image` | `category.deleteImage(googleAuthId, categoryId)` |
|
| `DELETE /api/category/:id/image` | `category.deleteImage(googleAuthId, categoryId)` |
|
||||||
| `GET /api/unit` | `unit.list(googleAuthId, companyId)` |
|
| `GET /api/unit` | `unit.list(googleAuthId)` |
|
||||||
| `PUT /api/unit` | `unit.upsert(googleAuthId, companyId, { si, basesi, basesifactor, symbol, name })` |
|
| `PUT /api/unit` | `unit.upsert(googleAuthId, { si, basesi, basesifactor, symbol, name })` |
|
||||||
| `DELETE /api/unit` | `unit.delete(googleAuthId, companyId, si)` |
|
| `DELETE /api/unit` | `unit.delete(googleAuthId, si)` |
|
||||||
| `GET /api/company/:id/settings` | `companysetting.list(googleAuthId, companyId, { frontendOnly: true })` |
|
| `GET /api/company/:id/settings` | `companysetting.list(googleAuthId, { frontendOnly: true })` |
|
||||||
| `PUT /api/company/:id/settings` | `companysetting.set(googleAuthId, companyId, { key, value, frontend? })` |
|
| `PUT /api/company/:id/settings` | `companysetting.set(googleAuthId, { key, value, frontend? })` |
|
||||||
| `DELETE /api/company/:id/settings/:key` | `companysetting.delete(googleAuthId, companyId, key)` |
|
| `DELETE /api/company/:id/settings/:key` | `companysetting.delete(googleAuthId, key)` |
|
||||||
| `GET /api/brand` | `brand.list(googleAuthId, companyId)` |
|
| `GET /api/brand` | `brand.list(googleAuthId)` |
|
||||||
| `PUT /api/brand` | `brand.upsert(googleAuthId, companyId, { name, gsprpinfo? })` |
|
| `PUT /api/brand` | `brand.upsert(googleAuthId, { name, gsprpinfo? })` |
|
||||||
| `DELETE /api/brand/:id` | `brand.delete(googleAuthId, companyId, id)` |
|
| `DELETE /api/brand/:id` | `brand.delete(googleAuthId, id)` |
|
||||||
| `GET /api/customergroup` | `customergroup.list(googleAuthId, companyId)` |
|
| `GET /api/customergroup` | `customergroup.list(googleAuthId)` |
|
||||||
| `POST /api/customergroup` | `customergroup.create(googleAuthId, companyId, { name })` |
|
| `POST /api/customergroup` | `customergroup.create(googleAuthId, { name })` |
|
||||||
| `PATCH /api/customergroup/:id` | `customergroup.update(googleAuthId, companyId, id, { name })` |
|
| `PATCH /api/customergroup/:id` | `customergroup.update(googleAuthId, id, { name })` |
|
||||||
| `PUT /api/customergroup/order` | `customergroup.order(googleAuthId, companyId, { customergroupIds })` |
|
| `PUT /api/customergroup/order` | `customergroup.order(googleAuthId, { customergroupIds })` |
|
||||||
| `DELETE /api/customergroup/:id` | `customergroup.delete(googleAuthId, companyId, id)` |
|
| `DELETE /api/customergroup/:id` | `customergroup.delete(googleAuthId, id)` |
|
||||||
| `GET /api/entity` | `entity.list(googleAuthId, companyId, { customergroupId?, role? })` |
|
| `GET /api/entity` | `entity.list(googleAuthId, { customergroupId?, role? })` |
|
||||||
| `GET /api/entity/:id` | `entity.getById(googleAuthId, companyId, id)` |
|
| `GET /api/entity/next-number` | `entity.peekNextNumber(googleAuthId)` |
|
||||||
| `POST /api/entity` | `entity.create(googleAuthId, companyId, { customergroupId, name, firstName? })` |
|
| `GET /api/entity/number-free` | `entity.isNumberFree(googleAuthId, number, { excludeEntityId? })` |
|
||||||
| `PATCH /api/entity/:id` | `entity.update(googleAuthId, companyId, id, { name?, firstName? })` |
|
| `GET /api/entity/:id` | `entity.getById(googleAuthId, id)` |
|
||||||
| `DELETE /api/entity/:id` | `entity.delete(googleAuthId, companyId, id)` |
|
| `POST /api/entity` | `entity.create(googleAuthId, { customergroupId, name, firstName?, number? })` |
|
||||||
| `GET /api/entity/:entityId/address` | `entityaddress.list(googleAuthId, companyId, entityId)` |
|
| `PATCH /api/entity/:id` | `entity.update(googleAuthId, id, { name?, firstName?, number? })` |
|
||||||
| `POST /api/entity/:entityId/address` | `entityaddress.create(googleAuthId, companyId, entityId, { addressType, … })` |
|
| `DELETE /api/entity/:id` | `entity.delete(googleAuthId, id)` |
|
||||||
| `PATCH /api/entity/:entityId/address/:id` | `entityaddress.update(googleAuthId, companyId, entityId, id, patch)` |
|
| `GET /api/entity/:entityId/address` | `entityaddress.list(googleAuthId, entityId)` |
|
||||||
| `DELETE /api/entity/:entityId/address/:id` | `entityaddress.delete(googleAuthId, companyId, entityId, id)` |
|
| `POST /api/entity/:entityId/address` | `entityaddress.create(googleAuthId, entityId, { addressType, … })` |
|
||||||
| `GET /api/entity/:entityId/contact` | `entitycontact.list(googleAuthId, companyId, entityId)` |
|
| `PATCH /api/entity/:entityId/address/:id` | `entityaddress.update(googleAuthId, entityId, id, patch)` |
|
||||||
| `POST /api/entity/:entityId/contact` | `entitycontact.create(googleAuthId, companyId, entityId, { contactType, contact })` |
|
| `DELETE /api/entity/:entityId/address/:id` | `entityaddress.delete(googleAuthId, entityId, id)` |
|
||||||
| `PATCH /api/entity/:entityId/contact/:id` | `entitycontact.update(googleAuthId, companyId, entityId, id, patch)` |
|
| `GET /api/entity/:entityId/contact` | `entitycontact.list(googleAuthId, entityId)` |
|
||||||
| `DELETE /api/entity/:entityId/contact/:id` | `entitycontact.delete(googleAuthId, companyId, entityId, id)` |
|
| `POST /api/entity/:entityId/contact` | `entitycontact.create(googleAuthId, entityId, { contactType, contact })` |
|
||||||
| `GET /api/supplier` | `supplier.list(googleAuthId, companyId)` |
|
| `PATCH /api/entity/:entityId/contact/:id` | `entitycontact.update(googleAuthId, entityId, id, patch)` |
|
||||||
| `POST /api/supplier` | `supplier.create(googleAuthId, companyId, { name })` |
|
| `DELETE /api/entity/:entityId/contact/:id` | `entitycontact.delete(googleAuthId, entityId, id)` |
|
||||||
| `PATCH /api/supplier/:id` | `supplier.update(googleAuthId, companyId, id, { name })` |
|
| `GET /api/supplier` | `supplier.list(googleAuthId)` |
|
||||||
| `DELETE /api/supplier/:id` | `supplier.delete(googleAuthId, companyId, id)` |
|
| `POST /api/supplier` | `supplier.create(googleAuthId, { name })` |
|
||||||
| `GET /api/delivery` | `delivery.list(googleAuthId, companyId)` |
|
| `PATCH /api/supplier/:id` | `supplier.update(googleAuthId, id, { name })` |
|
||||||
| `GET /api/delivery/:id` | `delivery.getById(googleAuthId, companyId, id)` |
|
| `DELETE /api/supplier/:id` | `supplier.delete(googleAuthId, id)` |
|
||||||
| `POST /api/delivery` | `delivery.create(googleAuthId, companyId, { number, date, supplierId?, lines })` |
|
| `GET /api/delivery` | `delivery.list(googleAuthId)` |
|
||||||
| `PATCH /api/delivery/:id` | `delivery.update(googleAuthId, companyId, id, { number?, date?, supplierId?, lines? })` |
|
| `GET /api/delivery/:id` | `delivery.getById(googleAuthId, id)` |
|
||||||
| `DELETE /api/delivery/:id` | `delivery.delete(googleAuthId, companyId, id)` |
|
| `POST /api/delivery` | `delivery.create(googleAuthId, { number, date, supplierId?, lines })` |
|
||||||
| `GET /api/quote` | `quote.list(googleAuthId, companyId)` |
|
| `PATCH /api/delivery/:id` | `delivery.update(googleAuthId, id, { number?, date?, supplierId?, lines? })` |
|
||||||
| `GET /api/quote/:id` | `quote.getById(googleAuthId, companyId, id)` |
|
| `DELETE /api/delivery/:id` | `delivery.delete(googleAuthId, id)` |
|
||||||
| `POST /api/quote` | `quote.create(googleAuthId, companyId, { number, date, entityId?, lines })` |
|
| `GET /api/quote` | `quote.list(googleAuthId)` |
|
||||||
| `PATCH /api/quote/:id` | `quote.update(googleAuthId, companyId, id, { number?, date?, entityId?, lines? })` |
|
| `GET /api/quote/:id` | `quote.getById(googleAuthId, id)` |
|
||||||
| `DELETE /api/quote/:id` | `quote.delete(googleAuthId, companyId, id)` |
|
| `POST /api/quote` | `quote.create(googleAuthId, { number, date, entityId?, lines })` |
|
||||||
| `GET /api/order` | `order.list(googleAuthId, companyId)` |
|
| `PATCH /api/quote/:id` | `quote.update(googleAuthId, id, { number?, date?, entityId?, lines? })` |
|
||||||
| `GET /api/order/:id` | `order.getById(googleAuthId, companyId, id)` |
|
| `DELETE /api/quote/:id` | `quote.delete(googleAuthId, id)` |
|
||||||
| `POST /api/order` | `order.create(googleAuthId, companyId, { number, date, entityId?, lines })` |
|
| `GET /api/order` | `order.list(googleAuthId)` |
|
||||||
| `PATCH /api/order/:id` | `order.update(googleAuthId, companyId, id, { number?, date?, entityId?, lines? })` |
|
| `GET /api/order/:id` | `order.getById(googleAuthId, id)` |
|
||||||
| `DELETE /api/order/:id` | `order.delete(googleAuthId, companyId, id)` |
|
| `POST /api/order` | `order.create(googleAuthId, { number, date, entityId?, lines })` |
|
||||||
| `GET /api/posterminal` | `posterminal.list(googleAuthId, companyId)` |
|
| `PATCH /api/order/:id` | `order.update(googleAuthId, id, { number?, date?, entityId?, lines? })` |
|
||||||
| `PUT /api/posterminal` | `posterminal.upsert(googleAuthId, companyId, { id?, name, token?, pairingpin })` |
|
| `DELETE /api/order/:id` | `order.delete(googleAuthId, id)` |
|
||||||
| `DELETE /api/posterminal/:id` | `posterminal.delete(googleAuthId, companyId, id)` |
|
| `GET /api/posterminal` | `posterminal.list(googleAuthId)` |
|
||||||
| `PUT /api/posterminal/:id/category/:categoryId` | `posterminal.setOn(googleAuthId, companyId, id, categoryId)` |
|
| `PUT /api/posterminal` | `posterminal.upsert(googleAuthId, { id?, name, token?, pairingpin })` |
|
||||||
| `DELETE /api/posterminal/:id/category/:categoryId` | `posterminal.setOff(googleAuthId, companyId, id, categoryId)` |
|
| `DELETE /api/posterminal/:id` | `posterminal.delete(googleAuthId, id)` |
|
||||||
| `PUT /api/posterminal/:id/categories` | `posterminal.setOnAll(googleAuthId, companyId, id)` |
|
| `PUT /api/posterminal/:id/category/:categoryId` | `posterminal.setOn(googleAuthId, id, categoryId)` |
|
||||||
| `DELETE /api/posterminal/:id/categories` | `posterminal.setOffAll(googleAuthId, companyId, id)` |
|
| `DELETE /api/posterminal/:id/category/:categoryId` | `posterminal.setOff(googleAuthId, id, categoryId)` |
|
||||||
|
| `PUT /api/posterminal/:id/categories` | `posterminal.setOnAll(googleAuthId, id)` |
|
||||||
|
| `DELETE /api/posterminal/:id/categories` | `posterminal.setOffAll(googleAuthId, id)` |
|
||||||
| `POST /api/article` | `article.createUnderParent({ googleAuthId, parentId, name })` |
|
| `POST /api/article` | `article.createUnderParent({ googleAuthId, parentId, name })` |
|
||||||
| `GET /api/article/:sku` | `article.getBySku(googleAuthId, sku)` |
|
| `GET /api/article/:sku` | `article.getBySku(googleAuthId, sku)` |
|
||||||
| `GET /api/article/:sku/history` | `article.getHistoryBySku(googleAuthId, sku)` |
|
| `GET /api/article/:sku/history` | `article.getHistoryBySku(googleAuthId, sku)` |
|
||||||
| `GET /api/articleIndex` | `article.listSearchIndex(googleAuthId, companyId)` |
|
| `GET /api/articleIndex` | `article.listSearchIndex(googleAuthId)` |
|
||||||
| `GET /api/article/export.zip` | `article.listExport(googleAuthId, companyId, categoryId?)` |
|
| `GET /api/article/export.zip` | `article.listExport(googleAuthId, categoryId?)` |
|
||||||
| `PATCH /api/article/:sku` | `article.updateBySku(googleAuthId, sku, { name?, unitamount?, unitSi? })` |
|
| `PATCH /api/article/:sku` | `article.updateBySku(googleAuthId, sku, { name?, unitamount?, unitSi? })` |
|
||||||
| `PUT /api/article/:sku/prices` | `article.setPricesBySku(googleAuthId, sku, [{ price, tax, minmultiplier? }])` |
|
| `PUT /api/article/:sku/prices` | `article.setPricesBySku(googleAuthId, sku, [{ price, tax, minmultiplier? }])` |
|
||||||
| `PUT /api/article/:sku/eans` | `article.setEansBySku(googleAuthId, sku, string[])` |
|
| `PUT /api/article/:sku/eans` | `article.setEansBySku(googleAuthId, sku, string[])` |
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ const INTERNAL_FILES = new Set([
|
|||||||
'ensureDefault.js',
|
'ensureDefault.js',
|
||||||
'ensureLieferantenGroup.js',
|
'ensureLieferantenGroup.js',
|
||||||
'resolveCompanyAccess.js',
|
'resolveCompanyAccess.js',
|
||||||
|
'resolveSelectedCompanyAccess.js',
|
||||||
'resolveCategoryAccess.js',
|
'resolveCategoryAccess.js',
|
||||||
'resolveCustomerGroupAccess.js',
|
'resolveCustomerGroupAccess.js',
|
||||||
'resolveEntityAccess.js',
|
'resolveEntityAccess.js',
|
||||||
@@ -53,6 +54,9 @@ const INTERNAL_FILES = new Set([
|
|||||||
'queryCategoryArticles.js',
|
'queryCategoryArticles.js',
|
||||||
'getCategoryPosterminalIds.js',
|
'getCategoryPosterminalIds.js',
|
||||||
'nextSku.js',
|
'nextSku.js',
|
||||||
|
'nextNumber.js',
|
||||||
|
'peekNumber.js',
|
||||||
|
'shape.js',
|
||||||
'createStore.js',
|
'createStore.js',
|
||||||
'index.js',
|
'index.js',
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ digraph schema {
|
|||||||
meta [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>meta</B></FONT></TD></TR><TR><TD PORT="key" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">key</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="value" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">value</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
meta [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>meta</B></FONT></TD></TR><TR><TD PORT="key" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">key</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="value" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">value</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(MAX)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||||
numbers [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>numbers</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="type" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">type</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="prefix" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">prefix</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="padding" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">padding</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="next" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">next</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
numbers [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>numbers</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="type" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">type</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="prefix" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">prefix</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="padding" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">padding</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="next" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">next</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||||
entityaddress [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entityaddress</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="first_name" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">first_name?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="street" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">street?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="streetnumber" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">streetnumber?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="zip" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">zip?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="city" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">city?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="county" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">county?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="addresstype" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">addresstype</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="sort" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">sort</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
entityaddress [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entityaddress</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="first_name" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">first_name?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="street" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">street?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="streetnumber" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">streetnumber?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="zip" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">zip?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="city" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">city?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="county" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">county?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="addresstype" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">addresstype</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="sort" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">sort</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||||
entity [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in2" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in3" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="4" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entity</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="customergroup_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>customergroup_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="first_name" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">first_name?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="created_at" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">created_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="updated_at" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">updated_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
entity [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in2" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in3" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="4" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entity</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="customergroup_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>customergroup_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="first_name" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">first_name?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="number" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">number?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="created_at" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">created_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="updated_at" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">updated_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||||
companyuser [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="2" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>companyuser</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="google_auth_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>google_auth_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
companyuser [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="2" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>companyuser</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="google_auth_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>google_auth_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||||
entitycontact [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entitycontact</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="contacttype" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">contacttype</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="contact" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">contact</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="sort" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">sort</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
entitycontact [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entitycontact</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="entity_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>entity_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="contacttype" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">contacttype</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="contact" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">contact</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="sort" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">sort</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||||
company [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in2" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in3" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in4" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in5" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in6" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in7" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in8" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in9" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="10" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>company</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="taxrate" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>taxrate</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="reducedtaxrate" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>reducedtaxrate</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="taxfreerate" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>taxfreerate</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="poscustomergroup_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>poscustomergroup_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="root_category_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>root_category_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="default_language_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>default_language_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
company [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in2" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in3" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in4" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in5" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in6" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in7" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in8" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in9" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="10" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>company</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="taxrate" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>taxrate</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="reducedtaxrate" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>reducedtaxrate</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="taxfreerate" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>taxfreerate</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="poscustomergroup_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>poscustomergroup_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="root_category_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>root_category_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="default_language_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>default_language_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
|
||||||
|
|||||||
@@ -251,46 +251,50 @@
|
|||||||
<!-- entity -->
|
<!-- entity -->
|
||||||
<g id="node5" class="node">
|
<g id="node5" class="node">
|
||||||
<title>entity</title>
|
<title>entity</title>
|
||||||
<polygon fill="#bee3f8" stroke="none" points="719.05,-1061.4 719.05,-1089.8 888.95,-1089.8 888.95,-1061.4 719.05,-1061.4"/>
|
<polygon fill="#bee3f8" stroke="none" points="719.05,-1074.8 719.05,-1103.2 888.95,-1103.2 888.95,-1074.8 719.05,-1074.8"/>
|
||||||
<polygon fill="none" stroke="#a0aec0" points="719.05,-1061.4 719.05,-1089.8 888.95,-1089.8 888.95,-1061.4 719.05,-1061.4"/>
|
<polygon fill="none" stroke="#a0aec0" points="719.05,-1074.8 719.05,-1103.2 888.95,-1103.2 888.95,-1074.8 719.05,-1074.8"/>
|
||||||
<polygon fill="#bee3f8" stroke="none" points="721.05,-1083.8 721.05,-1087.8 762.53,-1087.8 762.53,-1083.8 721.05,-1083.8"/>
|
<polygon fill="#bee3f8" stroke="none" points="721.05,-1097.2 721.05,-1101.2 762.53,-1101.2 762.53,-1097.2 721.05,-1097.2"/>
|
||||||
<polygon fill="#bee3f8" stroke="none" points="762.53,-1083.8 762.53,-1087.8 804,-1087.8 804,-1083.8 762.53,-1083.8"/>
|
<polygon fill="#bee3f8" stroke="none" points="762.53,-1097.2 762.53,-1101.2 804,-1101.2 804,-1097.2 762.53,-1097.2"/>
|
||||||
<polygon fill="#bee3f8" stroke="none" points="804,-1083.8 804,-1087.8 845.47,-1087.8 845.47,-1083.8 804,-1083.8"/>
|
<polygon fill="#bee3f8" stroke="none" points="804,-1097.2 804,-1101.2 845.47,-1101.2 845.47,-1097.2 804,-1097.2"/>
|
||||||
<polygon fill="#bee3f8" stroke="none" points="845.47,-1083.8 845.47,-1087.8 886.95,-1087.8 886.95,-1083.8 845.47,-1083.8"/>
|
<polygon fill="#bee3f8" stroke="none" points="845.47,-1097.2 845.47,-1101.2 886.95,-1101.2 886.95,-1097.2 845.47,-1097.2"/>
|
||||||
<text xml:space="preserve" text-anchor="start" x="788" y="-1071" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="12.00" fill="#1a365d">entity</text>
|
<text xml:space="preserve" text-anchor="start" x="788" y="-1084.4" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="12.00" fill="#1a365d">entity</text>
|
||||||
<polygon fill="#ebf8ff" stroke="none" points="719.05,-1034.6 719.05,-1061.4 888.95,-1061.4 888.95,-1034.6 719.05,-1034.6"/>
|
<polygon fill="#ebf8ff" stroke="none" points="719.05,-1048 719.05,-1074.8 888.95,-1074.8 888.95,-1048 719.05,-1048"/>
|
||||||
<polygon fill="none" stroke="#a0aec0" points="719.05,-1034.6 719.05,-1061.4 888.95,-1061.4 888.95,-1034.6 719.05,-1034.6"/>
|
<polygon fill="none" stroke="#a0aec0" points="719.05,-1048 719.05,-1074.8 888.95,-1074.8 888.95,-1048 719.05,-1048"/>
|
||||||
<text xml:space="preserve" text-anchor="start" x="724.05" y="-1044.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">id</text>
|
<text xml:space="preserve" text-anchor="start" x="724.05" y="-1058.2" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">id</text>
|
||||||
<text xml:space="preserve" text-anchor="start" x="854.45" y="-1046.3" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
|
<text xml:space="preserve" text-anchor="start" x="854.45" y="-1059.7" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
|
||||||
<text xml:space="preserve" text-anchor="start" x="871.45" y="-1046.3" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">PK</text>
|
<text xml:space="preserve" text-anchor="start" x="871.45" y="-1059.7" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">PK</text>
|
||||||
<polygon fill="#ebf8ff" stroke="none" points="719.05,-1007.8 719.05,-1034.6 888.95,-1034.6 888.95,-1007.8 719.05,-1007.8"/>
|
<polygon fill="#ebf8ff" stroke="none" points="719.05,-1021.2 719.05,-1048 888.95,-1048 888.95,-1021.2 719.05,-1021.2"/>
|
||||||
<polygon fill="none" stroke="#a0aec0" points="719.05,-1007.8 719.05,-1034.6 888.95,-1034.6 888.95,-1007.8 719.05,-1007.8"/>
|
<polygon fill="none" stroke="#a0aec0" points="719.05,-1021.2 719.05,-1048 888.95,-1048 888.95,-1021.2 719.05,-1021.2"/>
|
||||||
<text xml:space="preserve" text-anchor="start" x="724.05" y="-1018" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">customergroup_id</text>
|
<text xml:space="preserve" text-anchor="start" x="724.05" y="-1031.4" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">customergroup_id</text>
|
||||||
<text xml:space="preserve" text-anchor="start" x="854.95" y="-1019.5" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
|
<text xml:space="preserve" text-anchor="start" x="854.95" y="-1032.9" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
|
||||||
<text xml:space="preserve" text-anchor="start" x="871.95" y="-1019.5" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">FK</text>
|
<text xml:space="preserve" text-anchor="start" x="871.95" y="-1032.9" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">FK</text>
|
||||||
<polygon fill="#ffffff" stroke="none" points="719.05,-981 719.05,-1007.8 888.95,-1007.8 888.95,-981 719.05,-981"/>
|
<polygon fill="#ffffff" stroke="none" points="719.05,-994.4 719.05,-1021.2 888.95,-1021.2 888.95,-994.4 719.05,-994.4"/>
|
||||||
<polygon fill="none" stroke="#a0aec0" points="719.05,-981 719.05,-1007.8 888.95,-1007.8 888.95,-981 719.05,-981"/>
|
<polygon fill="none" stroke="#a0aec0" points="719.05,-994.4 719.05,-1021.2 888.95,-1021.2 888.95,-994.4 719.05,-994.4"/>
|
||||||
<text xml:space="preserve" text-anchor="start" x="724.05" y="-988.8" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">first_name?</text>
|
<text xml:space="preserve" text-anchor="start" x="724.05" y="-1002.2" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">first_name?</text>
|
||||||
<text xml:space="preserve" text-anchor="start" x="812.43" y="-990.8" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">NVARCHAR(255)</text>
|
<text xml:space="preserve" text-anchor="start" x="812.43" y="-1004.2" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">NVARCHAR(255)</text>
|
||||||
<polygon fill="#f7fafc" stroke="none" points="719.05,-954.2 719.05,-981 888.95,-981 888.95,-954.2 719.05,-954.2"/>
|
<polygon fill="#f7fafc" stroke="none" points="719.05,-967.6 719.05,-994.4 888.95,-994.4 888.95,-967.6 719.05,-967.6"/>
|
||||||
<polygon fill="none" stroke="#a0aec0" points="719.05,-954.2 719.05,-981 888.95,-981 888.95,-954.2 719.05,-954.2"/>
|
<polygon fill="none" stroke="#a0aec0" points="719.05,-967.6 719.05,-994.4 888.95,-994.4 888.95,-967.6 719.05,-967.6"/>
|
||||||
<text xml:space="preserve" text-anchor="start" x="724.05" y="-962" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">name</text>
|
<text xml:space="preserve" text-anchor="start" x="724.05" y="-975.4" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">name</text>
|
||||||
<text xml:space="preserve" text-anchor="start" x="812.43" y="-964" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">NVARCHAR(255)</text>
|
<text xml:space="preserve" text-anchor="start" x="812.43" y="-977.4" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">NVARCHAR(255)</text>
|
||||||
<polygon fill="#ffffff" stroke="none" points="719.05,-927.4 719.05,-954.2 888.95,-954.2 888.95,-927.4 719.05,-927.4"/>
|
<polygon fill="#ffffff" stroke="none" points="719.05,-940.8 719.05,-967.6 888.95,-967.6 888.95,-940.8 719.05,-940.8"/>
|
||||||
<polygon fill="none" stroke="#a0aec0" points="719.05,-927.4 719.05,-954.2 888.95,-954.2 888.95,-927.4 719.05,-927.4"/>
|
<polygon fill="none" stroke="#a0aec0" points="719.05,-940.8 719.05,-967.6 888.95,-967.6 888.95,-940.8 719.05,-940.8"/>
|
||||||
<text xml:space="preserve" text-anchor="start" x="724.05" y="-935.2" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">created_at</text>
|
<text xml:space="preserve" text-anchor="start" x="724.05" y="-948.6" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">number?</text>
|
||||||
<text xml:space="preserve" text-anchor="start" x="833.44" y="-937.2" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">DATETIME2</text>
|
<text xml:space="preserve" text-anchor="start" x="812.43" y="-950.6" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">NVARCHAR(100)</text>
|
||||||
<polygon fill="#f7fafc" stroke="none" points="719.05,-900.6 719.05,-927.4 888.95,-927.4 888.95,-900.6 719.05,-900.6"/>
|
<polygon fill="#f7fafc" stroke="none" points="719.05,-914 719.05,-940.8 888.95,-940.8 888.95,-914 719.05,-914"/>
|
||||||
<polygon fill="none" stroke="#a0aec0" points="719.05,-900.6 719.05,-927.4 888.95,-927.4 888.95,-900.6 719.05,-900.6"/>
|
<polygon fill="none" stroke="#a0aec0" points="719.05,-914 719.05,-940.8 888.95,-940.8 888.95,-914 719.05,-914"/>
|
||||||
<text xml:space="preserve" text-anchor="start" x="724.05" y="-908.4" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">updated_at</text>
|
<text xml:space="preserve" text-anchor="start" x="724.05" y="-921.8" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">created_at</text>
|
||||||
<text xml:space="preserve" text-anchor="start" x="833.44" y="-910.4" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">DATETIME2</text>
|
<text xml:space="preserve" text-anchor="start" x="833.44" y="-923.8" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">DATETIME2</text>
|
||||||
|
<polygon fill="#ffffff" stroke="none" points="719.05,-887.2 719.05,-914 888.95,-914 888.95,-887.2 719.05,-887.2"/>
|
||||||
|
<polygon fill="none" stroke="#a0aec0" points="719.05,-887.2 719.05,-914 888.95,-914 888.95,-887.2 719.05,-887.2"/>
|
||||||
|
<text xml:space="preserve" text-anchor="start" x="724.05" y="-895" font-family="Helvetica,sans-Serif" font-size="14.00" fill="#2d3748">updated_at</text>
|
||||||
|
<text xml:space="preserve" text-anchor="start" x="833.44" y="-897" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">DATETIME2</text>
|
||||||
</g>
|
</g>
|
||||||
<!-- entityaddress->entity -->
|
<!-- entityaddress->entity -->
|
||||||
<g id="edge11" class="edge">
|
<g id="edge11" class="edge">
|
||||||
<title>entityaddress:sw->entity:n</title>
|
<title>entityaddress:sw->entity:n</title>
|
||||||
<g id="a_edge11"><a xlink:title="FK_entityaddress_entity">
|
<g id="a_edge11"><a xlink:title="FK_entityaddress_entity">
|
||||||
<path fill="none" stroke="#9c4221" stroke-width="1.4" d="M770.61,-1506.8C706.89,-1443.08 778.65,-1197.26 783.05,-1097.69"/>
|
<path fill="none" stroke="#9c4221" stroke-width="1.4" d="M770.61,-1506.8C708.99,-1445.18 778.63,-1207.66 783.05,-1111.09"/>
|
||||||
<polygon fill="#9c4221" stroke="#9c4221" stroke-width="1.4" points="785.5,-1097.97 783.21,-1090.92 780.6,-1097.86 785.5,-1097.97"/>
|
<polygon fill="#9c4221" stroke="#9c4221" stroke-width="1.4" points="785.49,-1111.38 783.21,-1104.32 780.59,-1111.26 785.49,-1111.38"/>
|
||||||
</a>
|
</a>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
@@ -298,8 +302,8 @@
|
|||||||
<g id="edge10" class="edge">
|
<g id="edge10" class="edge">
|
||||||
<title>entity:nw->customergroup:n</title>
|
<title>entity:nw->customergroup:n</title>
|
||||||
<g id="a_edge10"><a xlink:title="FK_entity_customergroup">
|
<g id="a_edge10"><a xlink:title="FK_entity_customergroup">
|
||||||
<path fill="none" stroke="#276749" stroke-width="1.4" d="M718.05,-1034.6C718.05,-1034.6 617.38,-746.73 598.9,-693.88"/>
|
<path fill="none" stroke="#276749" stroke-width="1.4" d="M718.05,-1048C718.05,-1048 617.38,-749.08 598.9,-694.2"/>
|
||||||
<polygon fill="#276749" stroke="#276749" stroke-width="1.4" points="601.32,-693.4 596.7,-687.6 596.7,-695.02 601.32,-693.4"/>
|
<polygon fill="#276749" stroke="#276749" stroke-width="1.4" points="601.23,-693.46 596.68,-687.61 596.59,-695.02 601.23,-693.46"/>
|
||||||
</a>
|
</a>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
@@ -417,8 +421,8 @@
|
|||||||
<g id="edge12" class="edge">
|
<g id="edge12" class="edge">
|
||||||
<title>entitycontact:se->entity:n</title>
|
<title>entitycontact:se->entity:n</title>
|
||||||
<g id="a_edge12"><a xlink:title="FK_entitycontact_entity">
|
<g id="a_edge12"><a xlink:title="FK_entitycontact_entity">
|
||||||
<path fill="none" stroke="#0987a0" stroke-width="1.4" d="M1187.06,-1426.4C1213.58,-1399.87 1203.57,-1375.18 1186.06,-1342 1095.94,-1171.3 833.12,-1281.33 824.93,-1097.77"/>
|
<path fill="none" stroke="#0987a0" stroke-width="1.4" d="M1187.06,-1426.4C1213.58,-1399.87 1203.99,-1374.95 1186.06,-1342 1095.42,-1175.44 833.37,-1291.07 824.95,-1111.27"/>
|
||||||
<polygon fill="#0987a0" stroke="#0987a0" stroke-width="1.4" points="827.39,-1097.86 824.78,-1090.92 822.49,-1097.97 827.39,-1097.86"/>
|
<polygon fill="#0987a0" stroke="#0987a0" stroke-width="1.4" points="827.4,-1111.26 824.79,-1104.32 822.5,-1111.37 827.4,-1111.26"/>
|
||||||
</a>
|
</a>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
@@ -614,8 +618,8 @@
|
|||||||
<g id="edge13" class="edge">
|
<g id="edge13" class="edge">
|
||||||
<title>entityhistory:sw->entity:n</title>
|
<title>entityhistory:sw->entity:n</title>
|
||||||
<g id="a_edge13"><a xlink:title="FK_entityhistory_entity">
|
<g id="a_edge13"><a xlink:title="FK_entityhistory_entity">
|
||||||
<path fill="none" stroke="#553c9a" stroke-width="1.4" d="M1268.98,-1426.4C1215,-1372.42 1281.1,-1314.44 1228,-1259.6 1106.49,-1134.1 874.55,-1261.96 866.43,-1097.89"/>
|
<path fill="none" stroke="#553c9a" stroke-width="1.4" d="M1268.98,-1426.4C1215,-1372.42 1281.1,-1314.44 1228,-1259.6 1108.17,-1135.84 874.61,-1272.58 866.43,-1111.15"/>
|
||||||
<polygon fill="#553c9a" stroke="#553c9a" stroke-width="1.4" points="868.88,-1097.86 866.26,-1090.92 863.98,-1097.98 868.88,-1097.86"/>
|
<polygon fill="#553c9a" stroke="#553c9a" stroke-width="1.4" points="868.89,-1111.26 866.26,-1104.32 863.99,-1111.38 868.89,-1111.26"/>
|
||||||
</a>
|
</a>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
@@ -1627,8 +1631,8 @@
|
|||||||
<g id="edge47" class="edge">
|
<g id="edge47" class="edge">
|
||||||
<title>manifest:e->entity:n</title>
|
<title>manifest:e->entity:n</title>
|
||||||
<g id="a_edge47"><a xlink:title="FK_manifest_entity">
|
<g id="a_edge47"><a xlink:title="FK_manifest_entity">
|
||||||
<path fill="none" stroke="#3182ce" stroke-width="1.4" d="M222.49,-644.8C370.25,-644.8 405.07,-704.07 515,-802.8 629.39,-905.53 576.16,-1014.04 711.05,-1087.8 719.11,-1092.21 730.21,-1097.31 736.63,-1096.04"/>
|
<path fill="none" stroke="#3182ce" stroke-width="1.4" d="M222.49,-644.8C370.25,-644.8 406.12,-702.91 515,-802.8 631.93,-910.08 572.64,-1023.59 711.05,-1101.2 719.06,-1105.69 730.18,-1110.77 736.62,-1109.47"/>
|
||||||
<polygon fill="#3182ce" stroke="#3182ce" stroke-width="1.4" points="738.5,-1097.65 740.56,-1090.53 734.51,-1094.81 738.5,-1097.65"/>
|
<polygon fill="#3182ce" stroke="#3182ce" stroke-width="1.4" points="738.5,-1111.05 740.56,-1103.93 734.51,-1108.21 738.5,-1111.05"/>
|
||||||
</a>
|
</a>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 187 KiB |
@@ -99,17 +99,17 @@ const MENU = {
|
|||||||
{
|
{
|
||||||
value: 'unit.list',
|
value: 'unit.list',
|
||||||
label: 'list',
|
label: 'list',
|
||||||
hint: 'googleAuthId, companyId → rows',
|
hint: 'googleAuthId → rows',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'unit.upsert',
|
value: 'unit.upsert',
|
||||||
label: 'upsert',
|
label: 'upsert',
|
||||||
hint: 'googleAuthId, companyId, JSON unit → row',
|
hint: 'googleAuthId, JSON unit → row',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'unit.delete',
|
value: 'unit.delete',
|
||||||
label: 'delete',
|
label: 'delete',
|
||||||
hint: 'googleAuthId, companyId, si',
|
hint: 'googleAuthId, si',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -119,22 +119,22 @@ const MENU = {
|
|||||||
{
|
{
|
||||||
value: 'companysetting.list',
|
value: 'companysetting.list',
|
||||||
label: 'list',
|
label: 'list',
|
||||||
hint: 'googleAuthId, companyId, frontendOnly? → rows',
|
hint: 'googleAuthId, frontendOnly? → rows',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'companysetting.get',
|
value: 'companysetting.get',
|
||||||
label: 'get',
|
label: 'get',
|
||||||
hint: 'googleAuthId, companyId, key → row',
|
hint: 'googleAuthId, key → row',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'companysetting.set',
|
value: 'companysetting.set',
|
||||||
label: 'set',
|
label: 'set',
|
||||||
hint: 'googleAuthId, companyId, JSON setting → row',
|
hint: 'googleAuthId, JSON setting → row',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'companysetting.delete',
|
value: 'companysetting.delete',
|
||||||
label: 'delete',
|
label: 'delete',
|
||||||
hint: 'googleAuthId, companyId, key',
|
hint: 'googleAuthId, key',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -144,56 +144,58 @@ const MENU = {
|
|||||||
{
|
{
|
||||||
value: 'brand.list',
|
value: 'brand.list',
|
||||||
label: 'list',
|
label: 'list',
|
||||||
hint: 'googleAuthId, companyId → rows',
|
hint: 'googleAuthId → rows',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'brand.upsert',
|
value: 'brand.upsert',
|
||||||
label: 'upsert',
|
label: 'upsert',
|
||||||
hint: 'googleAuthId, companyId, JSON brand → row',
|
hint: 'googleAuthId, JSON brand → row',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'brand.delete',
|
value: 'brand.delete',
|
||||||
label: 'delete',
|
label: 'delete',
|
||||||
hint: 'googleAuthId, companyId, id',
|
hint: 'googleAuthId, id',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
customergroup: {
|
customergroup: {
|
||||||
label: 'customergroup',
|
label: 'customergroup',
|
||||||
items: [
|
items: [
|
||||||
{ value: 'customergroup.list', label: 'list', hint: 'googleAuthId, companyId → rows' },
|
{ value: 'customergroup.list', label: 'list', hint: 'googleAuthId → rows' },
|
||||||
{ value: 'customergroup.create', label: 'create', hint: 'googleAuthId, companyId, name → row' },
|
{ value: 'customergroup.create', label: 'create', hint: 'googleAuthId, name → row' },
|
||||||
{ value: 'customergroup.update', label: 'update', hint: 'googleAuthId, companyId, id, name → row' },
|
{ value: 'customergroup.update', label: 'update', hint: 'googleAuthId, id, name → row' },
|
||||||
{ value: 'customergroup.order', label: 'order', hint: 'googleAuthId, companyId, JSON customergroupIds → { customergroupIds }' },
|
{ value: 'customergroup.order', label: 'order', hint: 'googleAuthId, JSON customergroupIds → { customergroupIds }' },
|
||||||
{ value: 'customergroup.delete', label: 'delete', hint: 'googleAuthId, companyId, id' },
|
{ value: 'customergroup.delete', label: 'delete', hint: 'googleAuthId, id' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
entity: {
|
entity: {
|
||||||
label: 'entity',
|
label: 'entity',
|
||||||
items: [
|
items: [
|
||||||
{ value: 'entity.list', label: 'list', hint: 'googleAuthId, companyId, customergroupId?|role=customer → rows' },
|
{ value: 'entity.list', label: 'list', hint: 'googleAuthId, customergroupId?|role=customer → rows' },
|
||||||
{ value: 'entity.getById', label: 'getById', hint: 'googleAuthId, companyId, id → row' },
|
{ value: 'entity.getById', label: 'getById', hint: 'googleAuthId, id → row' },
|
||||||
{ value: 'entity.create', label: 'create', hint: 'googleAuthId, companyId, JSON → row' },
|
{ value: 'entity.create', label: 'create', hint: 'googleAuthId, JSON → row' },
|
||||||
{ value: 'entity.update', label: 'update', hint: 'googleAuthId, companyId, id, JSON → row' },
|
{ value: 'entity.update', label: 'update', hint: 'googleAuthId, id, JSON → row' },
|
||||||
{ value: 'entity.delete', label: 'delete', hint: 'googleAuthId, companyId, id' },
|
{ value: 'entity.delete', label: 'delete', hint: 'googleAuthId, id' },
|
||||||
|
{ value: 'entity.peekNextNumber', label: 'peekNextNumber', hint: 'googleAuthId → next number' },
|
||||||
|
{ value: 'entity.isNumberFree', label: 'isNumberFree', hint: 'googleAuthId, number, excludeEntityId? → bool' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
entityaddress: {
|
entityaddress: {
|
||||||
label: 'entityaddress',
|
label: 'entityaddress',
|
||||||
items: [
|
items: [
|
||||||
{ value: 'entityaddress.list', label: 'list', hint: 'googleAuthId, companyId, entityId → rows' },
|
{ value: 'entityaddress.list', label: 'list', hint: 'googleAuthId, entityId → rows' },
|
||||||
{ value: 'entityaddress.create', label: 'create', hint: 'googleAuthId, companyId, entityId, JSON → row' },
|
{ value: 'entityaddress.create', label: 'create', hint: 'googleAuthId, entityId, JSON → row' },
|
||||||
{ value: 'entityaddress.update', label: 'update', hint: 'googleAuthId, companyId, entityId, id, JSON → row' },
|
{ value: 'entityaddress.update', label: 'update', hint: 'googleAuthId, entityId, id, JSON → row' },
|
||||||
{ value: 'entityaddress.delete', label: 'delete', hint: 'googleAuthId, companyId, entityId, id' },
|
{ value: 'entityaddress.delete', label: 'delete', hint: 'googleAuthId, entityId, id' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
entitycontact: {
|
entitycontact: {
|
||||||
label: 'entitycontact',
|
label: 'entitycontact',
|
||||||
items: [
|
items: [
|
||||||
{ value: 'entitycontact.list', label: 'list', hint: 'googleAuthId, companyId, entityId → rows' },
|
{ value: 'entitycontact.list', label: 'list', hint: 'googleAuthId, entityId → rows' },
|
||||||
{ value: 'entitycontact.create', label: 'create', hint: 'googleAuthId, companyId, entityId, JSON → row' },
|
{ value: 'entitycontact.create', label: 'create', hint: 'googleAuthId, entityId, JSON → row' },
|
||||||
{ value: 'entitycontact.update', label: 'update', hint: 'googleAuthId, companyId, entityId, id, JSON → row' },
|
{ value: 'entitycontact.update', label: 'update', hint: 'googleAuthId, entityId, id, JSON → row' },
|
||||||
{ value: 'entitycontact.delete', label: 'delete', hint: 'googleAuthId, companyId, entityId, id' },
|
{ value: 'entitycontact.delete', label: 'delete', hint: 'googleAuthId, entityId, id' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
supplier: {
|
supplier: {
|
||||||
@@ -202,22 +204,22 @@ const MENU = {
|
|||||||
{
|
{
|
||||||
value: 'supplier.list',
|
value: 'supplier.list',
|
||||||
label: 'list',
|
label: 'list',
|
||||||
hint: 'googleAuthId, companyId → rows',
|
hint: 'googleAuthId → rows',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'supplier.create',
|
value: 'supplier.create',
|
||||||
label: 'create',
|
label: 'create',
|
||||||
hint: 'googleAuthId, companyId, name → row',
|
hint: 'googleAuthId, name → row',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'supplier.update',
|
value: 'supplier.update',
|
||||||
label: 'update',
|
label: 'update',
|
||||||
hint: 'googleAuthId, companyId, id, name → row',
|
hint: 'googleAuthId, id, name → row',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'supplier.delete',
|
value: 'supplier.delete',
|
||||||
label: 'delete',
|
label: 'delete',
|
||||||
hint: 'googleAuthId, companyId, id',
|
hint: 'googleAuthId, id',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -227,27 +229,27 @@ const MENU = {
|
|||||||
{
|
{
|
||||||
value: 'delivery.list',
|
value: 'delivery.list',
|
||||||
label: 'list',
|
label: 'list',
|
||||||
hint: 'googleAuthId, companyId → summaries',
|
hint: 'googleAuthId → summaries',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'delivery.getById',
|
value: 'delivery.getById',
|
||||||
label: 'getById',
|
label: 'getById',
|
||||||
hint: 'googleAuthId, companyId, id → delivery',
|
hint: 'googleAuthId, id → delivery',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'delivery.create',
|
value: 'delivery.create',
|
||||||
label: 'create',
|
label: 'create',
|
||||||
hint: 'googleAuthId, companyId, JSON body → delivery',
|
hint: 'googleAuthId, JSON body → delivery',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'delivery.update',
|
value: 'delivery.update',
|
||||||
label: 'update',
|
label: 'update',
|
||||||
hint: 'googleAuthId, companyId, id, JSON patch → delivery',
|
hint: 'googleAuthId, id, JSON patch → delivery',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'delivery.delete',
|
value: 'delivery.delete',
|
||||||
label: 'delete',
|
label: 'delete',
|
||||||
hint: 'googleAuthId, companyId, id',
|
hint: 'googleAuthId, id',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -257,27 +259,27 @@ const MENU = {
|
|||||||
{
|
{
|
||||||
value: 'quote.list',
|
value: 'quote.list',
|
||||||
label: 'list',
|
label: 'list',
|
||||||
hint: 'googleAuthId, companyId → summaries',
|
hint: 'googleAuthId → summaries',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'quote.getById',
|
value: 'quote.getById',
|
||||||
label: 'getById',
|
label: 'getById',
|
||||||
hint: 'googleAuthId, companyId, id → quote',
|
hint: 'googleAuthId, id → quote',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'quote.create',
|
value: 'quote.create',
|
||||||
label: 'create',
|
label: 'create',
|
||||||
hint: 'googleAuthId, companyId, JSON body → quote',
|
hint: 'googleAuthId, JSON body → quote',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'quote.update',
|
value: 'quote.update',
|
||||||
label: 'update',
|
label: 'update',
|
||||||
hint: 'googleAuthId, companyId, id, JSON patch → quote',
|
hint: 'googleAuthId, id, JSON patch → quote',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'quote.delete',
|
value: 'quote.delete',
|
||||||
label: 'delete',
|
label: 'delete',
|
||||||
hint: 'googleAuthId, companyId, id',
|
hint: 'googleAuthId, id',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -287,27 +289,27 @@ const MENU = {
|
|||||||
{
|
{
|
||||||
value: 'order.list',
|
value: 'order.list',
|
||||||
label: 'list',
|
label: 'list',
|
||||||
hint: 'googleAuthId, companyId → summaries',
|
hint: 'googleAuthId → summaries',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'order.getById',
|
value: 'order.getById',
|
||||||
label: 'getById',
|
label: 'getById',
|
||||||
hint: 'googleAuthId, companyId, id → order',
|
hint: 'googleAuthId, id → order',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'order.create',
|
value: 'order.create',
|
||||||
label: 'create',
|
label: 'create',
|
||||||
hint: 'googleAuthId, companyId, JSON body → order',
|
hint: 'googleAuthId, JSON body → order',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'order.update',
|
value: 'order.update',
|
||||||
label: 'update',
|
label: 'update',
|
||||||
hint: 'googleAuthId, companyId, id, JSON patch → order',
|
hint: 'googleAuthId, id, JSON patch → order',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'order.delete',
|
value: 'order.delete',
|
||||||
label: 'delete',
|
label: 'delete',
|
||||||
hint: 'googleAuthId, companyId, id',
|
hint: 'googleAuthId, id',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -319,7 +321,7 @@ const MENU = {
|
|||||||
{ value: 'category.move', label: 'move', hint: 'googleAuthId, id, parentId → row' },
|
{ value: 'category.move', label: 'move', hint: 'googleAuthId, id, parentId → row' },
|
||||||
{ value: 'category.order', label: 'order', hint: 'googleAuthId, parentId, JSON categoryIds' },
|
{ value: 'category.order', label: 'order', hint: 'googleAuthId, parentId, JSON categoryIds' },
|
||||||
{ value: 'category.delete', label: 'delete', hint: 'googleAuthId, id' },
|
{ value: 'category.delete', label: 'delete', hint: 'googleAuthId, id' },
|
||||||
{ value: 'category.getTreeForCompany', label: 'getTreeForCompany', hint: 'googleAuthId, companyId → rows' },
|
{ value: 'category.getTreeForCompany', label: 'getTreeForCompany', hint: 'googleAuthId → rows' },
|
||||||
{ value: 'category.getCategoryArticles', label: 'getCategoryArticles', hint: 'googleAuthId, categoryId → rows' },
|
{ value: 'category.getCategoryArticles', label: 'getCategoryArticles', hint: 'googleAuthId, categoryId → rows' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -597,18 +599,14 @@ async function runMethod(client, action) {
|
|||||||
case 'unit.list': {
|
case 'unit.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.unit.list(Number(googleAuthId), Number(companyId)),
|
await client.unit.list(Number(googleAuthId)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
case 'unit.upsert': {
|
case 'unit.upsert': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const unitJson = await askText('unit JSON', {
|
const unitJson = await askText('unit JSON', {
|
||||||
placeholder:
|
placeholder:
|
||||||
'{"si":"ml","basesi":"l","basesifactor":0.001,"symbol":"ml","name":"Milliliter"}',
|
'{"si":"ml","basesi":"l","basesifactor":0.001,"symbol":"ml","name":"Milliliter"}',
|
||||||
@@ -629,7 +627,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.unit.upsert(
|
await client.unit.upsert(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
JSON.parse(unitJson),
|
JSON.parse(unitJson),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -637,27 +634,23 @@ async function runMethod(client, action) {
|
|||||||
case 'unit.delete': {
|
case 'unit.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const si = await askText('si', {
|
const si = await askText('si', {
|
||||||
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
||||||
});
|
});
|
||||||
if (si == null) return;
|
if (si == null) return;
|
||||||
await client.unit.delete(Number(googleAuthId), Number(companyId), si);
|
await client.unit.delete(Number(googleAuthId), si);
|
||||||
return ['ok', true];
|
return ['ok', true];
|
||||||
}
|
}
|
||||||
case 'companysetting.list': {
|
case 'companysetting.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const frontendOnly = await askText('frontendOnly (true/false)', {
|
const frontendOnly = await askText('frontendOnly (true/false)', {
|
||||||
placeholder: 'false',
|
placeholder: 'false',
|
||||||
});
|
});
|
||||||
if (frontendOnly == null) return;
|
if (frontendOnly == null) return;
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.companysetting.list(Number(googleAuthId), Number(companyId), {
|
await client.companysetting.list(Number(googleAuthId), {
|
||||||
frontendOnly: frontendOnly.trim().toLowerCase() === 'true',
|
frontendOnly: frontendOnly.trim().toLowerCase() === 'true',
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
@@ -665,8 +658,6 @@ async function runMethod(client, action) {
|
|||||||
case 'companysetting.get': {
|
case 'companysetting.get': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const key = await askText('key', {
|
const key = await askText('key', {
|
||||||
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
||||||
});
|
});
|
||||||
@@ -679,7 +670,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.companysetting.get(
|
await client.companysetting.get(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
key,
|
key,
|
||||||
{ frontendOnly: frontendOnly.trim().toLowerCase() === 'true' },
|
{ frontendOnly: frontendOnly.trim().toLowerCase() === 'true' },
|
||||||
),
|
),
|
||||||
@@ -688,8 +678,6 @@ async function runMethod(client, action) {
|
|||||||
case 'companysetting.set': {
|
case 'companysetting.set': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const settingJson = await askText('setting JSON', {
|
const settingJson = await askText('setting JSON', {
|
||||||
placeholder: '{"key":"theme","value":"dark","frontend":true}',
|
placeholder: '{"key":"theme","value":"dark","frontend":true}',
|
||||||
validate: (v) => {
|
validate: (v) => {
|
||||||
@@ -709,7 +697,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.companysetting.set(
|
await client.companysetting.set(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
JSON.parse(settingJson),
|
JSON.parse(settingJson),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -717,15 +704,12 @@ async function runMethod(client, action) {
|
|||||||
case 'companysetting.delete': {
|
case 'companysetting.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const key = await askText('key', {
|
const key = await askText('key', {
|
||||||
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
||||||
});
|
});
|
||||||
if (key == null) return;
|
if (key == null) return;
|
||||||
await client.companysetting.delete(
|
await client.companysetting.delete(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
key,
|
key,
|
||||||
);
|
);
|
||||||
return ['ok', true];
|
return ['ok', true];
|
||||||
@@ -733,18 +717,14 @@ async function runMethod(client, action) {
|
|||||||
case 'brand.list': {
|
case 'brand.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.brand.list(Number(googleAuthId), Number(companyId)),
|
await client.brand.list(Number(googleAuthId)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
case 'brand.upsert': {
|
case 'brand.upsert': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const brandJson = await askText('brand JSON', {
|
const brandJson = await askText('brand JSON', {
|
||||||
placeholder: '{"name":"Nike","gsprpinfo":"..."}',
|
placeholder: '{"name":"Nike","gsprpinfo":"..."}',
|
||||||
validate: (v) => {
|
validate: (v) => {
|
||||||
@@ -764,7 +744,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.brand.upsert(
|
await client.brand.upsert(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
JSON.parse(brandJson),
|
JSON.parse(brandJson),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -772,28 +751,22 @@ async function runMethod(client, action) {
|
|||||||
case 'brand.delete': {
|
case 'brand.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('brand id');
|
const id = await askInt('brand id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
await client.brand.delete(Number(googleAuthId), Number(companyId), id);
|
await client.brand.delete(Number(googleAuthId), id);
|
||||||
return ['ok', true];
|
return ['ok', true];
|
||||||
}
|
}
|
||||||
case 'customergroup.list': {
|
case 'customergroup.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.customergroup.list(Number(googleAuthId), Number(companyId)),
|
await client.customergroup.list(Number(googleAuthId)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
case 'customergroup.create': {
|
case 'customergroup.create': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const name = await askText('name', {
|
const name = await askText('name', {
|
||||||
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
||||||
});
|
});
|
||||||
@@ -802,7 +775,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.customergroup.create(
|
await client.customergroup.create(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
{ name },
|
{ name },
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -810,8 +782,6 @@ async function runMethod(client, action) {
|
|||||||
case 'customergroup.update': {
|
case 'customergroup.update': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('customergroup id');
|
const id = await askInt('customergroup id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
const name = await askText('name', {
|
const name = await askText('name', {
|
||||||
@@ -822,7 +792,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.customergroup.update(
|
await client.customergroup.update(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
{ name },
|
{ name },
|
||||||
),
|
),
|
||||||
@@ -831,8 +800,6 @@ async function runMethod(client, action) {
|
|||||||
case 'customergroup.order': {
|
case 'customergroup.order': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const idsJson = await askText('customergroupIds JSON', {
|
const idsJson = await askText('customergroupIds JSON', {
|
||||||
placeholder: '[3,1,2]',
|
placeholder: '[3,1,2]',
|
||||||
validate: (v) => {
|
validate: (v) => {
|
||||||
@@ -850,7 +817,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.customergroup.order(
|
await client.customergroup.order(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
{ customergroupIds: JSON.parse(idsJson) },
|
{ customergroupIds: JSON.parse(idsJson) },
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -858,13 +824,10 @@ async function runMethod(client, action) {
|
|||||||
case 'customergroup.delete': {
|
case 'customergroup.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('customergroup id');
|
const id = await askInt('customergroup id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
await client.customergroup.delete(
|
await client.customergroup.delete(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
);
|
);
|
||||||
return ['ok', true];
|
return ['ok', true];
|
||||||
@@ -872,8 +835,6 @@ async function runMethod(client, action) {
|
|||||||
case 'entity.list': {
|
case 'entity.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const roleRaw = await askText('role (customer|empty)', {
|
const roleRaw = await askText('role (customer|empty)', {
|
||||||
placeholder: '',
|
placeholder: '',
|
||||||
validate: (v) => {
|
validate: (v) => {
|
||||||
@@ -900,7 +861,7 @@ async function runMethod(client, action) {
|
|||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.entity.list(Number(googleAuthId), Number(companyId), {
|
await client.entity.list(Number(googleAuthId), {
|
||||||
customergroupId,
|
customergroupId,
|
||||||
role,
|
role,
|
||||||
}),
|
}),
|
||||||
@@ -909,15 +870,12 @@ async function runMethod(client, action) {
|
|||||||
case 'entity.getById': {
|
case 'entity.getById': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('entity id');
|
const id = await askInt('entity id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
return [
|
return [
|
||||||
'result',
|
'result',
|
||||||
await client.entity.getById(
|
await client.entity.getById(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -925,10 +883,8 @@ async function runMethod(client, action) {
|
|||||||
case 'entity.create': {
|
case 'entity.create': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const bodyJson = await askText('entity JSON', {
|
const bodyJson = await askText('entity JSON', {
|
||||||
placeholder: '{"customergroupId":1,"name":"Acme","firstName":null}',
|
placeholder: '{"customergroupId":1,"name":"Acme","firstName":null,"number":null}',
|
||||||
validate: (v) => {
|
validate: (v) => {
|
||||||
if (!v?.trim()) return 'Required';
|
if (!v?.trim()) return 'Required';
|
||||||
try {
|
try {
|
||||||
@@ -943,7 +899,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.entity.create(
|
await client.entity.create(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
JSON.parse(bodyJson),
|
JSON.parse(bodyJson),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -951,12 +906,10 @@ async function runMethod(client, action) {
|
|||||||
case 'entity.update': {
|
case 'entity.update': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('entity id');
|
const id = await askInt('entity id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
const patchJson = await askText('patch JSON', {
|
const patchJson = await askText('patch JSON', {
|
||||||
placeholder: '{"name":"Acme","firstName":"Ada"}',
|
placeholder: '{"name":"Acme","firstName":"Ada","number":"C-1"}',
|
||||||
validate: (v) => {
|
validate: (v) => {
|
||||||
if (!v?.trim()) return 'Required';
|
if (!v?.trim()) return 'Required';
|
||||||
try {
|
try {
|
||||||
@@ -971,7 +924,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.entity.update(
|
await client.entity.update(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
JSON.parse(patchJson),
|
JSON.parse(patchJson),
|
||||||
),
|
),
|
||||||
@@ -980,29 +932,61 @@ async function runMethod(client, action) {
|
|||||||
case 'entity.delete': {
|
case 'entity.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('entity id');
|
const id = await askInt('entity id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
await client.entity.delete(
|
await client.entity.delete(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
);
|
);
|
||||||
return ['ok', true];
|
return ['ok', true];
|
||||||
}
|
}
|
||||||
|
case 'entity.peekNextNumber': {
|
||||||
|
const googleAuthId = await askInt('google_auth id');
|
||||||
|
if (googleAuthId == null) return;
|
||||||
|
return [
|
||||||
|
'result',
|
||||||
|
await client.entity.peekNextNumber(
|
||||||
|
Number(googleAuthId),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
case 'entity.isNumberFree': {
|
||||||
|
const googleAuthId = await askInt('google_auth id');
|
||||||
|
if (googleAuthId == null) return;
|
||||||
|
const number = await askText('number', {
|
||||||
|
validate: (v) => (v?.trim() ? undefined : 'Required'),
|
||||||
|
});
|
||||||
|
if (number == null) return;
|
||||||
|
const excludeRaw = await askText('exclude entity id (optional)', {
|
||||||
|
placeholder: 'leave empty',
|
||||||
|
validate: (v) => {
|
||||||
|
const t = v?.trim() ?? '';
|
||||||
|
if (!t) return undefined;
|
||||||
|
return /^\d+$/.test(t) ? undefined : 'Integer or empty';
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (excludeRaw == null) return;
|
||||||
|
const excludeEntityId = excludeRaw.trim()
|
||||||
|
? Number(excludeRaw.trim())
|
||||||
|
: null;
|
||||||
|
return [
|
||||||
|
'result',
|
||||||
|
await client.entity.isNumberFree(
|
||||||
|
Number(googleAuthId),
|
||||||
|
number.trim(),
|
||||||
|
excludeEntityId == null ? {} : { excludeEntityId },
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
case 'entityaddress.list': {
|
case 'entityaddress.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const entityId = await askInt('entity id');
|
const entityId = await askInt('entity id');
|
||||||
if (entityId == null) return;
|
if (entityId == null) return;
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.entityaddress.list(
|
await client.entityaddress.list(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(entityId),
|
Number(entityId),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -1010,8 +994,6 @@ async function runMethod(client, action) {
|
|||||||
case 'entityaddress.create': {
|
case 'entityaddress.create': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const entityId = await askInt('entity id');
|
const entityId = await askInt('entity id');
|
||||||
if (entityId == null) return;
|
if (entityId == null) return;
|
||||||
const bodyJson = await askText('address JSON', {
|
const bodyJson = await askText('address JSON', {
|
||||||
@@ -1031,7 +1013,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.entityaddress.create(
|
await client.entityaddress.create(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(entityId),
|
Number(entityId),
|
||||||
JSON.parse(bodyJson),
|
JSON.parse(bodyJson),
|
||||||
),
|
),
|
||||||
@@ -1040,8 +1021,6 @@ async function runMethod(client, action) {
|
|||||||
case 'entityaddress.update': {
|
case 'entityaddress.update': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const entityId = await askInt('entity id');
|
const entityId = await askInt('entity id');
|
||||||
if (entityId == null) return;
|
if (entityId == null) return;
|
||||||
const id = await askInt('address id');
|
const id = await askInt('address id');
|
||||||
@@ -1062,7 +1041,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.entityaddress.update(
|
await client.entityaddress.update(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(entityId),
|
Number(entityId),
|
||||||
Number(id),
|
Number(id),
|
||||||
JSON.parse(patchJson),
|
JSON.parse(patchJson),
|
||||||
@@ -1072,15 +1050,12 @@ async function runMethod(client, action) {
|
|||||||
case 'entityaddress.delete': {
|
case 'entityaddress.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const entityId = await askInt('entity id');
|
const entityId = await askInt('entity id');
|
||||||
if (entityId == null) return;
|
if (entityId == null) return;
|
||||||
const id = await askInt('address id');
|
const id = await askInt('address id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
await client.entityaddress.delete(
|
await client.entityaddress.delete(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(entityId),
|
Number(entityId),
|
||||||
Number(id),
|
Number(id),
|
||||||
);
|
);
|
||||||
@@ -1089,15 +1064,12 @@ async function runMethod(client, action) {
|
|||||||
case 'entitycontact.list': {
|
case 'entitycontact.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const entityId = await askInt('entity id');
|
const entityId = await askInt('entity id');
|
||||||
if (entityId == null) return;
|
if (entityId == null) return;
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.entitycontact.list(
|
await client.entitycontact.list(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(entityId),
|
Number(entityId),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -1105,8 +1077,6 @@ async function runMethod(client, action) {
|
|||||||
case 'entitycontact.create': {
|
case 'entitycontact.create': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const entityId = await askInt('entity id');
|
const entityId = await askInt('entity id');
|
||||||
if (entityId == null) return;
|
if (entityId == null) return;
|
||||||
const bodyJson = await askText('contact JSON', {
|
const bodyJson = await askText('contact JSON', {
|
||||||
@@ -1125,7 +1095,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.entitycontact.create(
|
await client.entitycontact.create(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(entityId),
|
Number(entityId),
|
||||||
JSON.parse(bodyJson),
|
JSON.parse(bodyJson),
|
||||||
),
|
),
|
||||||
@@ -1134,8 +1103,6 @@ async function runMethod(client, action) {
|
|||||||
case 'entitycontact.update': {
|
case 'entitycontact.update': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const entityId = await askInt('entity id');
|
const entityId = await askInt('entity id');
|
||||||
if (entityId == null) return;
|
if (entityId == null) return;
|
||||||
const id = await askInt('contact id');
|
const id = await askInt('contact id');
|
||||||
@@ -1156,7 +1123,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.entitycontact.update(
|
await client.entitycontact.update(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(entityId),
|
Number(entityId),
|
||||||
Number(id),
|
Number(id),
|
||||||
JSON.parse(patchJson),
|
JSON.parse(patchJson),
|
||||||
@@ -1166,15 +1132,12 @@ async function runMethod(client, action) {
|
|||||||
case 'entitycontact.delete': {
|
case 'entitycontact.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const entityId = await askInt('entity id');
|
const entityId = await askInt('entity id');
|
||||||
if (entityId == null) return;
|
if (entityId == null) return;
|
||||||
const id = await askInt('contact id');
|
const id = await askInt('contact id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
await client.entitycontact.delete(
|
await client.entitycontact.delete(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(entityId),
|
Number(entityId),
|
||||||
Number(id),
|
Number(id),
|
||||||
);
|
);
|
||||||
@@ -1183,25 +1146,21 @@ async function runMethod(client, action) {
|
|||||||
case 'supplier.list': {
|
case 'supplier.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.supplier.list(Number(googleAuthId), Number(companyId)),
|
await client.supplier.list(Number(googleAuthId)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
case 'supplier.create': {
|
case 'supplier.create': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const name = await askText('name', {
|
const name = await askText('name', {
|
||||||
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
validate: (v) => (!v?.trim() ? 'Required' : undefined),
|
||||||
});
|
});
|
||||||
if (name == null) return;
|
if (name == null) return;
|
||||||
return [
|
return [
|
||||||
'result',
|
'result',
|
||||||
await client.supplier.create(Number(googleAuthId), Number(companyId), {
|
await client.supplier.create(Number(googleAuthId), {
|
||||||
name,
|
name,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
@@ -1209,8 +1168,6 @@ async function runMethod(client, action) {
|
|||||||
case 'supplier.update': {
|
case 'supplier.update': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('supplier id');
|
const id = await askInt('supplier id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
const name = await askText('name', {
|
const name = await askText('name', {
|
||||||
@@ -1221,7 +1178,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.supplier.update(
|
await client.supplier.update(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
{ name },
|
{ name },
|
||||||
),
|
),
|
||||||
@@ -1230,13 +1186,10 @@ async function runMethod(client, action) {
|
|||||||
case 'supplier.delete': {
|
case 'supplier.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('supplier id');
|
const id = await askInt('supplier id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
await client.supplier.delete(
|
await client.supplier.delete(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
);
|
);
|
||||||
return ['ok', true];
|
return ['ok', true];
|
||||||
@@ -1244,25 +1197,20 @@ async function runMethod(client, action) {
|
|||||||
case 'delivery.list': {
|
case 'delivery.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.delivery.list(Number(googleAuthId), Number(companyId)),
|
await client.delivery.list(Number(googleAuthId)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
case 'delivery.getById': {
|
case 'delivery.getById': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('delivery id');
|
const id = await askInt('delivery id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
return [
|
return [
|
||||||
'result',
|
'result',
|
||||||
await client.delivery.getById(
|
await client.delivery.getById(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -1270,8 +1218,6 @@ async function runMethod(client, action) {
|
|||||||
case 'delivery.create': {
|
case 'delivery.create': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const bodyJson = await askText('delivery JSON', {
|
const bodyJson = await askText('delivery JSON', {
|
||||||
placeholder:
|
placeholder:
|
||||||
'{"number":"DHL-123","date":"2026-08-10","supplierId":1,"lines":[{"sku":"1","amount":10,"net":99.5,"tax":19}]}',
|
'{"number":"DHL-123","date":"2026-08-10","supplierId":1,"lines":[{"sku":"1","amount":10,"net":99.5,"tax":19}]}',
|
||||||
@@ -1292,7 +1238,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.delivery.create(
|
await client.delivery.create(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
JSON.parse(bodyJson),
|
JSON.parse(bodyJson),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -1300,8 +1245,6 @@ async function runMethod(client, action) {
|
|||||||
case 'delivery.update': {
|
case 'delivery.update': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('delivery id');
|
const id = await askInt('delivery id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
const patchJson = await askText('patch JSON', {
|
const patchJson = await askText('patch JSON', {
|
||||||
@@ -1323,7 +1266,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.delivery.update(
|
await client.delivery.update(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
JSON.parse(patchJson),
|
JSON.parse(patchJson),
|
||||||
),
|
),
|
||||||
@@ -1332,13 +1274,10 @@ async function runMethod(client, action) {
|
|||||||
case 'delivery.delete': {
|
case 'delivery.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('delivery id');
|
const id = await askInt('delivery id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
await client.delivery.delete(
|
await client.delivery.delete(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
);
|
);
|
||||||
return ['ok', true];
|
return ['ok', true];
|
||||||
@@ -1346,25 +1285,20 @@ async function runMethod(client, action) {
|
|||||||
case 'quote.list': {
|
case 'quote.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.quote.list(Number(googleAuthId), Number(companyId)),
|
await client.quote.list(Number(googleAuthId)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
case 'quote.getById': {
|
case 'quote.getById': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('quote id');
|
const id = await askInt('quote id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
return [
|
return [
|
||||||
'result',
|
'result',
|
||||||
await client.quote.getById(
|
await client.quote.getById(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -1372,8 +1306,6 @@ async function runMethod(client, action) {
|
|||||||
case 'quote.create': {
|
case 'quote.create': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const bodyJson = await askText('quote JSON', {
|
const bodyJson = await askText('quote JSON', {
|
||||||
placeholder:
|
placeholder:
|
||||||
'{"number":"A-2026-001","date":"2026-09-01","entityId":12,"lines":[{"sku":"1","amount":10,"net":99.5,"tax":19}]}',
|
'{"number":"A-2026-001","date":"2026-09-01","entityId":12,"lines":[{"sku":"1","amount":10,"net":99.5,"tax":19}]}',
|
||||||
@@ -1394,7 +1326,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.quote.create(
|
await client.quote.create(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
JSON.parse(bodyJson),
|
JSON.parse(bodyJson),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -1402,8 +1333,6 @@ async function runMethod(client, action) {
|
|||||||
case 'quote.update': {
|
case 'quote.update': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('quote id');
|
const id = await askInt('quote id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
const patchJson = await askText('patch JSON', {
|
const patchJson = await askText('patch JSON', {
|
||||||
@@ -1425,7 +1354,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.quote.update(
|
await client.quote.update(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
JSON.parse(patchJson),
|
JSON.parse(patchJson),
|
||||||
),
|
),
|
||||||
@@ -1434,13 +1362,10 @@ async function runMethod(client, action) {
|
|||||||
case 'quote.delete': {
|
case 'quote.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('quote id');
|
const id = await askInt('quote id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
await client.quote.delete(
|
await client.quote.delete(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
);
|
);
|
||||||
return ['ok', true];
|
return ['ok', true];
|
||||||
@@ -1448,25 +1373,20 @@ async function runMethod(client, action) {
|
|||||||
case 'order.list': {
|
case 'order.list': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
return [
|
return [
|
||||||
'result[]',
|
'result[]',
|
||||||
await client.order.list(Number(googleAuthId), Number(companyId)),
|
await client.order.list(Number(googleAuthId)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
case 'order.getById': {
|
case 'order.getById': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('order id');
|
const id = await askInt('order id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
return [
|
return [
|
||||||
'result',
|
'result',
|
||||||
await client.order.getById(
|
await client.order.getById(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -1474,8 +1394,6 @@ async function runMethod(client, action) {
|
|||||||
case 'order.create': {
|
case 'order.create': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const bodyJson = await askText('order JSON', {
|
const bodyJson = await askText('order JSON', {
|
||||||
placeholder:
|
placeholder:
|
||||||
'{"number":"B-2026-001","date":"2026-09-15","entityId":12,"lines":[{"sku":"1","amount":10,"net":99.5,"tax":19}]}',
|
'{"number":"B-2026-001","date":"2026-09-15","entityId":12,"lines":[{"sku":"1","amount":10,"net":99.5,"tax":19}]}',
|
||||||
@@ -1496,7 +1414,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.order.create(
|
await client.order.create(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
JSON.parse(bodyJson),
|
JSON.parse(bodyJson),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -1504,8 +1421,6 @@ async function runMethod(client, action) {
|
|||||||
case 'order.update': {
|
case 'order.update': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('order id');
|
const id = await askInt('order id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
const patchJson = await askText('patch JSON', {
|
const patchJson = await askText('patch JSON', {
|
||||||
@@ -1527,7 +1442,6 @@ async function runMethod(client, action) {
|
|||||||
'result',
|
'result',
|
||||||
await client.order.update(
|
await client.order.update(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
JSON.parse(patchJson),
|
JSON.parse(patchJson),
|
||||||
),
|
),
|
||||||
@@ -1536,13 +1450,10 @@ async function runMethod(client, action) {
|
|||||||
case 'order.delete': {
|
case 'order.delete': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
const id = await askInt('order id');
|
const id = await askInt('order id');
|
||||||
if (id == null) return;
|
if (id == null) return;
|
||||||
await client.order.delete(
|
await client.order.delete(
|
||||||
Number(googleAuthId),
|
Number(googleAuthId),
|
||||||
Number(companyId),
|
|
||||||
Number(id),
|
Number(id),
|
||||||
);
|
);
|
||||||
return ['ok', true];
|
return ['ok', true];
|
||||||
@@ -1657,11 +1568,9 @@ async function runMethod(client, action) {
|
|||||||
case 'category.getTreeForCompany': {
|
case 'category.getTreeForCompany': {
|
||||||
const googleAuthId = await askInt('google_auth id');
|
const googleAuthId = await askInt('google_auth id');
|
||||||
if (googleAuthId == null) return;
|
if (googleAuthId == null) return;
|
||||||
const companyId = await askInt('company id');
|
|
||||||
if (companyId == null) return;
|
|
||||||
return [
|
return [
|
||||||
'rows',
|
'rows',
|
||||||
await client.category.getTreeForCompany(Number(googleAuthId), Number(companyId)),
|
await client.category.getTreeForCompany(Number(googleAuthId)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
case 'category.getCategoryArticles': {
|
case 'category.getCategoryArticles': {
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ import entityGetById from './store/entity/getById.js';
|
|||||||
import entityCreate from './store/entity/create.js';
|
import entityCreate from './store/entity/create.js';
|
||||||
import entityUpdate from './store/entity/update.js';
|
import entityUpdate from './store/entity/update.js';
|
||||||
import entityDelete from './store/entity/delete.js';
|
import entityDelete from './store/entity/delete.js';
|
||||||
|
import entityPeekNextNumber from './store/entity/peekNextNumber.js';
|
||||||
|
import entityIsNumberFree from './store/entity/isNumberFree.js';
|
||||||
import entityaddressList from './store/entityaddress/list.js';
|
import entityaddressList from './store/entityaddress/list.js';
|
||||||
import entityaddressCreate from './store/entityaddress/create.js';
|
import entityaddressCreate from './store/entityaddress/create.js';
|
||||||
import entityaddressUpdate from './store/entityaddress/update.js';
|
import entityaddressUpdate from './store/entityaddress/update.js';
|
||||||
@@ -192,6 +194,8 @@ export default class LibDashStore {
|
|||||||
create: entityCreate(pool),
|
create: entityCreate(pool),
|
||||||
update: entityUpdate(pool),
|
update: entityUpdate(pool),
|
||||||
delete: entityDelete(pool),
|
delete: entityDelete(pool),
|
||||||
|
peekNextNumber: entityPeekNextNumber(pool),
|
||||||
|
isNumberFree: entityIsNumberFree(pool),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.entityaddress = {
|
this.entityaddress = {
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ BEGIN
|
|||||||
customergroup_id INT NOT NULL,
|
customergroup_id INT NOT NULL,
|
||||||
first_name NVARCHAR(255) NULL,
|
first_name NVARCHAR(255) NULL,
|
||||||
name NVARCHAR(255) NOT NULL,
|
name NVARCHAR(255) NOT NULL,
|
||||||
|
[number] NVARCHAR(100) NULL,
|
||||||
created_at DATETIME2 NOT NULL CONSTRAINT DF_entity_created_at DEFAULT SYSUTCDATETIME(),
|
created_at DATETIME2 NOT NULL CONSTRAINT DF_entity_created_at DEFAULT SYSUTCDATETIME(),
|
||||||
updated_at DATETIME2 NOT NULL CONSTRAINT DF_entity_updated_at DEFAULT SYSUTCDATETIME(),
|
updated_at DATETIME2 NOT NULL CONSTRAINT DF_entity_updated_at DEFAULT SYSUTCDATETIME(),
|
||||||
CONSTRAINT FK_entity_customergroup FOREIGN KEY (customergroup_id) REFERENCES customergroup(id) ON DELETE CASCADE
|
CONSTRAINT FK_entity_customergroup FOREIGN KEY (customergroup_id) REFERENCES customergroup(id) ON DELETE CASCADE
|
||||||
@@ -165,6 +166,35 @@ BEGIN
|
|||||||
END
|
END
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
/** Unique (company_id, number) for non-null entity numbers via customergroup. */
|
||||||
|
export const INIT_ENTITY_COMPANY_NUMBER_UQ = `
|
||||||
|
IF OBJECT_ID(N'dbo.v_entity_company_number', N'V') IS NULL
|
||||||
|
BEGIN
|
||||||
|
EXEC('
|
||||||
|
CREATE VIEW dbo.v_entity_company_number
|
||||||
|
WITH SCHEMABINDING
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
e.id AS entity_id,
|
||||||
|
cg.company_id,
|
||||||
|
e.[number]
|
||||||
|
FROM dbo.entity AS e
|
||||||
|
INNER JOIN dbo.customergroup AS cg ON cg.id = e.customergroup_id
|
||||||
|
WHERE e.[number] IS NOT NULL
|
||||||
|
');
|
||||||
|
END
|
||||||
|
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1 FROM sys.indexes
|
||||||
|
WHERE name = N'UQ_entity_company_number'
|
||||||
|
AND object_id = OBJECT_ID(N'dbo.v_entity_company_number')
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
|
CREATE UNIQUE CLUSTERED INDEX UQ_entity_company_number
|
||||||
|
ON dbo.v_entity_company_number (company_id, [number]);
|
||||||
|
END
|
||||||
|
`;
|
||||||
|
|
||||||
export const INIT_ENTITYADDRESS = `
|
export const INIT_ENTITYADDRESS = `
|
||||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'entityaddress')
|
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'entityaddress')
|
||||||
BEGIN
|
BEGIN
|
||||||
@@ -601,6 +631,43 @@ END
|
|||||||
');
|
');
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
// EXEC dbo.peeknextnumberwithprefixandpadding
|
||||||
|
// @company_id = 1, @type = N'entity', @value = @n OUTPUT;
|
||||||
|
export const INIT_PEEK_NEXT_NUMBER_WITH_PREFIX_AND_PADDING = `
|
||||||
|
IF OBJECT_ID(N'dbo.peeknextnumberwithprefixandpadding', N'P') IS NOT NULL
|
||||||
|
DROP PROCEDURE dbo.peeknextnumberwithprefixandpadding;
|
||||||
|
|
||||||
|
EXEC('
|
||||||
|
CREATE PROCEDURE dbo.peeknextnumberwithprefixandpadding
|
||||||
|
@company_id INT,
|
||||||
|
@type NVARCHAR(100),
|
||||||
|
@value NVARCHAR(100) OUTPUT
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON;
|
||||||
|
|
||||||
|
DECLARE @prefix NVARCHAR(50);
|
||||||
|
DECLARE @padding INT;
|
||||||
|
DECLARE @num INT;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
@prefix = n.prefix,
|
||||||
|
@padding = n.padding,
|
||||||
|
@num = n.[next]
|
||||||
|
FROM numbers n WITH (UPDLOCK, ROWLOCK)
|
||||||
|
WHERE n.company_id = @company_id AND n.[type] = @type;
|
||||||
|
|
||||||
|
IF @@ROWCOUNT = 0
|
||||||
|
THROW 50000, ''Number type not found for company'', 1;
|
||||||
|
|
||||||
|
SET @value = @prefix + CASE
|
||||||
|
WHEN @padding > 0 THEN RIGHT(REPLICATE(''0'', @padding) + CAST(@num AS NVARCHAR(20)), @padding)
|
||||||
|
ELSE CAST(@num AS NVARCHAR(20))
|
||||||
|
END;
|
||||||
|
END
|
||||||
|
');
|
||||||
|
`;
|
||||||
|
|
||||||
export const INIT_COMPANYUSER = `
|
export const INIT_COMPANYUSER = `
|
||||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'companyuser')
|
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'companyuser')
|
||||||
BEGIN
|
BEGIN
|
||||||
@@ -686,6 +753,7 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_CUSTOMERGROUP,
|
INIT_CUSTOMERGROUP,
|
||||||
INIT_COMPANY_POS_CUSTOMERGROUP_FK,
|
INIT_COMPANY_POS_CUSTOMERGROUP_FK,
|
||||||
INIT_ENTITY,
|
INIT_ENTITY,
|
||||||
|
INIT_ENTITY_COMPANY_NUMBER_UQ,
|
||||||
INIT_ENTITYADDRESS,
|
INIT_ENTITYADDRESS,
|
||||||
INIT_ENTITYCONTACT,
|
INIT_ENTITYCONTACT,
|
||||||
INIT_UNIT,
|
INIT_UNIT,
|
||||||
@@ -709,6 +777,7 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_LEDGER,
|
INIT_LEDGER,
|
||||||
INIT_NUMBERS,
|
INIT_NUMBERS,
|
||||||
INIT_GET_NEXT_NUMBER_WITH_PREFIX_AND_PADDING,
|
INIT_GET_NEXT_NUMBER_WITH_PREFIX_AND_PADDING,
|
||||||
|
INIT_PEEK_NEXT_NUMBER_WITH_PREFIX_AND_PADDING,
|
||||||
INIT_COMPANYUSER,
|
INIT_COMPANYUSER,
|
||||||
INIT_ARTICLEHISTORY,
|
INIT_ARTICLEHISTORY,
|
||||||
INIT_ENTITYHISTORY,
|
INIT_ENTITYHISTORY,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export const ENTITY_COLUMNS = `
|
|||||||
e.customergroup_id AS customergroupId,
|
e.customergroup_id AS customergroupId,
|
||||||
e.first_name AS firstName,
|
e.first_name AS firstName,
|
||||||
e.name,
|
e.name,
|
||||||
|
e.[number] AS number,
|
||||||
e.created_at AS createdAt,
|
e.created_at AS createdAt,
|
||||||
e.updated_at AS updatedAt
|
e.updated_at AS updatedAt
|
||||||
`;
|
`;
|
||||||
@@ -49,6 +50,16 @@ WHERE e.id = @id
|
|||||||
AND cg.company_id = @companyId
|
AND cg.company_id = @companyId
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
/** Occupied when another entity in the company already has this number. */
|
||||||
|
export const NUMBER_TAKEN_IN_COMPANY = `
|
||||||
|
SELECT TOP 1 e.id
|
||||||
|
FROM entity e
|
||||||
|
INNER JOIN customergroup cg ON cg.id = e.customergroup_id
|
||||||
|
WHERE cg.company_id = @companyId
|
||||||
|
AND e.[number] = @number
|
||||||
|
AND (@excludeEntityId IS NULL OR e.id <> @excludeEntityId)
|
||||||
|
`;
|
||||||
|
|
||||||
/** Customer entity: company-scoped and not Lieferanten/POS. */
|
/** Customer entity: company-scoped and not Lieferanten/POS. */
|
||||||
export const GET_CUSTOMER_BY_ID = `
|
export const GET_CUSTOMER_BY_ID = `
|
||||||
SELECT
|
SELECT
|
||||||
@@ -87,15 +98,16 @@ WHERE e.id = @id
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const CREATE = `
|
export const CREATE = `
|
||||||
INSERT INTO entity (customergroup_id, first_name, name)
|
INSERT INTO entity (customergroup_id, first_name, name, [number])
|
||||||
OUTPUT
|
OUTPUT
|
||||||
INSERTED.id,
|
INSERTED.id,
|
||||||
INSERTED.customergroup_id AS customergroupId,
|
INSERTED.customergroup_id AS customergroupId,
|
||||||
INSERTED.first_name AS firstName,
|
INSERTED.first_name AS firstName,
|
||||||
INSERTED.name,
|
INSERTED.name,
|
||||||
|
INSERTED.[number] AS number,
|
||||||
INSERTED.created_at AS createdAt,
|
INSERTED.created_at AS createdAt,
|
||||||
INSERTED.updated_at AS updatedAt
|
INSERTED.updated_at AS updatedAt
|
||||||
VALUES (@customergroupId, @firstName, @name)
|
VALUES (@customergroupId, @firstName, @name, @number)
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const UPDATE = `
|
export const UPDATE = `
|
||||||
@@ -103,12 +115,14 @@ UPDATE entity
|
|||||||
SET
|
SET
|
||||||
first_name = @firstName,
|
first_name = @firstName,
|
||||||
name = @name,
|
name = @name,
|
||||||
|
[number] = @number,
|
||||||
updated_at = SYSUTCDATETIME()
|
updated_at = SYSUTCDATETIME()
|
||||||
OUTPUT
|
OUTPUT
|
||||||
INSERTED.id,
|
INSERTED.id,
|
||||||
INSERTED.customergroup_id AS customergroupId,
|
INSERTED.customergroup_id AS customergroupId,
|
||||||
INSERTED.first_name AS firstName,
|
INSERTED.first_name AS firstName,
|
||||||
INSERTED.name,
|
INSERTED.name,
|
||||||
|
INSERTED.[number] AS number,
|
||||||
INSERTED.created_at AS createdAt,
|
INSERTED.created_at AS createdAt,
|
||||||
INSERTED.updated_at AS updatedAt
|
INSERTED.updated_at AS updatedAt
|
||||||
WHERE id = @id
|
WHERE id = @id
|
||||||
|
|||||||
@@ -40,7 +40,12 @@ export const TABLES = [
|
|||||||
'meta',
|
'meta',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const PROCEDURES = ['getnextnumberwithprefixandpadding'];
|
export const PROCEDURES = [
|
||||||
|
'getnextnumberwithprefixandpadding',
|
||||||
|
'peeknextnumberwithprefixandpadding',
|
||||||
|
];
|
||||||
|
|
||||||
|
export const VIEWS = ['v_entity_company_number'];
|
||||||
|
|
||||||
/** Drop before tables — breaks company ↔ customergroup cycle for purge. */
|
/** Drop before tables — breaks company ↔ customergroup cycle for purge. */
|
||||||
export const CONSTRAINTS = [
|
export const CONSTRAINTS = [
|
||||||
@@ -54,6 +59,10 @@ export function buildPurgeSql() {
|
|||||||
(name) =>
|
(name) =>
|
||||||
`IF OBJECT_ID(N'dbo.${name}', N'P') IS NOT NULL DROP PROCEDURE dbo.[${name}];`,
|
`IF OBJECT_ID(N'dbo.${name}', N'P') IS NOT NULL DROP PROCEDURE dbo.[${name}];`,
|
||||||
),
|
),
|
||||||
|
...VIEWS.map(
|
||||||
|
(name) =>
|
||||||
|
`IF OBJECT_ID(N'dbo.${name}', N'V') IS NOT NULL DROP VIEW dbo.[${name}];`,
|
||||||
|
),
|
||||||
...CONSTRAINTS,
|
...CONSTRAINTS,
|
||||||
...TABLES.map(
|
...TABLES.map(
|
||||||
(name) =>
|
(name) =>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_ARTICLE_EXPORT, GET_CATEGORY_TREE_FLAT } from '../../sql/article.js';
|
import { GET_ARTICLE_EXPORT, GET_CATEGORY_TREE_FLAT } from '../../sql/article.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveCategoryAccess from '../category/resolveCategoryAccess.js';
|
import resolveCategoryAccess from '../category/resolveCategoryAccess.js';
|
||||||
|
|
||||||
const ROOT_CATEGORY_NAME = 'Home';
|
const ROOT_CATEGORY_NAME = 'Home';
|
||||||
@@ -19,18 +19,16 @@ function parseJsonArray(raw) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = listExport(pool);
|
* const fn = listExport(pool);
|
||||||
* const articles = await fn(42, 1, null);
|
* const articles = await fn(42, null);
|
||||||
* // => [{ id, sku, name, slug, unitSi, net, taxRate, eans, categoryBreadcrumbs, fullHashes, ... }]
|
* // => [{ id, sku, name, slug, unitSi, net, taxRate, eans, categoryBreadcrumbs, fullHashes, ... }]
|
||||||
*/
|
*/
|
||||||
export default function listExport(pool) {
|
export default function listExport(pool) {
|
||||||
const companyAccess = resolveCompanyAccess(pool);
|
const companyAccess = resolveSelectedCompanyAccess(pool);
|
||||||
const categoryAccess = resolveCategoryAccess(pool);
|
const categoryAccess = resolveCategoryAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, categoryId) => {
|
return async (googleAuthId, categoryId) => {
|
||||||
const { languageId, posCustomerGroupId, rootCategoryId } = await companyAccess(
|
const { languageId, posCustomerGroupId, rootCategoryId } =
|
||||||
googleAuthId,
|
await companyAccess(googleAuthId);
|
||||||
companyId,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Default to the company's root category when no specific category is given.
|
// Default to the company's root category when no specific category is given.
|
||||||
let exportCategoryId = rootCategoryId;
|
let exportCategoryId = rootCategoryId;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { SEARCH_ARTICLES } from '../../sql/article.js';
|
import { SEARCH_ARTICLES } from '../../sql/article.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a lightweight search index of all articles for a company.
|
* Returns a lightweight search index of all articles for a company.
|
||||||
@@ -9,14 +9,14 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = listSearchIndex(pool);
|
* const fn = listSearchIndex(pool);
|
||||||
* const articles = await fn(42, 1);
|
* const articles = await fn(42);
|
||||||
* // => [{ id, sku, name, eans, categoryIds }]
|
* // => [{ id, sku, name, eans, categoryIds }]
|
||||||
*/
|
*/
|
||||||
export default function listSearchIndex(pool) {
|
export default function listSearchIndex(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId) => {
|
return async (googleAuthId) => {
|
||||||
const { rootCategoryId, languageId } = await access(googleAuthId, companyId);
|
const { companyId, rootCategoryId, languageId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELETE_BY_COMPANY_AND_ID } from '../../sql/brand.js';
|
import { DELETE_BY_COMPANY_AND_ID } from '../../sql/brand.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a brand for a company by its id.
|
* Deletes a brand for a company by its id.
|
||||||
@@ -9,17 +9,17 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = del(pool);
|
* const fn = del(pool);
|
||||||
* await fn(42, 1, 3);
|
* await fn(42, 3);
|
||||||
*/
|
*/
|
||||||
export default function del(pool) {
|
export default function del(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id) => {
|
return async (googleAuthId, id) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Brand not found');
|
throw new Error('Brand not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await pool
|
const result = await pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LIST_BY_COMPANY } from '../../sql/brand.js';
|
import { LIST_BY_COMPANY } from '../../sql/brand.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists the brands of a company.
|
* Lists the brands of a company.
|
||||||
@@ -9,14 +9,14 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = list(pool);
|
* const fn = list(pool);
|
||||||
* const brands = await fn(42, 1);
|
* const brands = await fn(42);
|
||||||
* // => [{ id, name, gsprpinfo }]
|
* // => [{ id, name, gsprpinfo }]
|
||||||
*/
|
*/
|
||||||
export default function list(pool) {
|
export default function list(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId) => {
|
return async (googleAuthId) => {
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
GET_BY_COMPANY_AND_NAME,
|
GET_BY_COMPANY_AND_NAME,
|
||||||
UPDATE_BY_ID,
|
UPDATE_BY_ID,
|
||||||
} from '../../sql/brand.js';
|
} from '../../sql/brand.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates or updates a brand for a company, keyed by name.
|
* Creates or updates a brand for a company, keyed by name.
|
||||||
@@ -13,20 +13,20 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = upsert(pool);
|
* const fn = upsert(pool);
|
||||||
* const brand = await fn(42, 1, { name: 'Coca-Cola', gsprpinfo: 'x' });
|
* const brand = await fn(42, { name: 'Coca-Cola', gsprpinfo: 'x' });
|
||||||
* // => { id, name, gsprpinfo }
|
* // => { id, name, gsprpinfo }
|
||||||
*/
|
*/
|
||||||
export default function upsert(pool) {
|
export default function upsert(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, input = {}) => {
|
return async (googleAuthId, input = {}) => {
|
||||||
const name = input.name?.trim();
|
const name = input.name?.trim();
|
||||||
if (!name) {
|
if (!name) {
|
||||||
throw new Error('Invalid brand');
|
throw new Error('Invalid brand');
|
||||||
}
|
}
|
||||||
const gsprpinfo = input.gsprpinfo ?? null;
|
const gsprpinfo = input.gsprpinfo ?? null;
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const existing = await pool
|
const existing = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_TREE_FOR_COMPANY } from '../../sql/category.js';
|
import { GET_TREE_FOR_COMPANY } from '../../sql/category.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import queryCategoryArticles from './queryCategoryArticles.js';
|
import queryCategoryArticles from './queryCategoryArticles.js';
|
||||||
import getCategoryPosterminalIds from '../posterminal/getCategoryPosterminalIds.js';
|
import getCategoryPosterminalIds from '../posterminal/getCategoryPosterminalIds.js';
|
||||||
|
|
||||||
@@ -12,19 +12,17 @@ import getCategoryPosterminalIds from '../posterminal/getCategoryPosterminalIds.
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = getTreeForCompany(pool);
|
* const fn = getTreeForCompany(pool);
|
||||||
* const tree = await fn(42, 1);
|
* const tree = await fn(42);
|
||||||
* // => { languageId, tree: [{ id, posterminalIds, ... }], articles: [...] }
|
* // => { languageId, tree: [{ id, posterminalIds, ... }], articles: [...] }
|
||||||
*/
|
*/
|
||||||
export default function getTreeForCompany(pool) {
|
export default function getTreeForCompany(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const articles = queryCategoryArticles(pool);
|
const articles = queryCategoryArticles(pool);
|
||||||
const posterminalIds = getCategoryPosterminalIds(pool);
|
const posterminalIds = getCategoryPosterminalIds(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId) => {
|
return async (googleAuthId) => {
|
||||||
const { rootCategoryId, languageId, posCustomerGroupId } = await access(
|
const { companyId, rootCategoryId, languageId, posCustomerGroupId } =
|
||||||
googleAuthId,
|
await access(googleAuthId);
|
||||||
companyId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [treeResult, articleRows, ptMap] = await Promise.all([
|
const [treeResult, articleRows, ptMap] = await Promise.all([
|
||||||
pool
|
pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELETE_BY_COMPANY_AND_KEY } from '../../sql/companysetting.js';
|
import { DELETE_BY_COMPANY_AND_KEY } from '../../sql/companysetting.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a company setting by key.
|
* Deletes a company setting by key.
|
||||||
@@ -9,17 +9,17 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = del(pool);
|
* const fn = del(pool);
|
||||||
* await fn(42, 1, 'theme');
|
* await fn(42, 'theme');
|
||||||
*/
|
*/
|
||||||
export default function del(pool) {
|
export default function del(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, key) => {
|
return async (googleAuthId, key) => {
|
||||||
if (!key?.trim()) {
|
if (!key?.trim()) {
|
||||||
throw new Error('Setting not found');
|
throw new Error('Setting not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_BY_COMPANY_AND_KEY } from '../../sql/companysetting.js';
|
import { GET_BY_COMPANY_AND_KEY } from '../../sql/companysetting.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import shapeSetting from './shapeSetting.js';
|
import shapeSetting from './shapeSetting.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,18 +10,18 @@ import shapeSetting from './shapeSetting.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = get(pool);
|
* const fn = get(pool);
|
||||||
* const setting = await fn(42, 1, 'theme');
|
* const setting = await fn(42, 'theme');
|
||||||
* // => { key, value, frontend }
|
* // => { key, value, frontend }
|
||||||
*/
|
*/
|
||||||
export default function get(pool) {
|
export default function get(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, key, { frontendOnly = false } = {}) => {
|
return async (googleAuthId, key, { frontendOnly = false } = {}) => {
|
||||||
if (!key?.trim()) {
|
if (!key?.trim()) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {
|
|||||||
LIST_BY_COMPANY,
|
LIST_BY_COMPANY,
|
||||||
LIST_BY_COMPANY_FRONTEND,
|
LIST_BY_COMPANY_FRONTEND,
|
||||||
} from '../../sql/companysetting.js';
|
} from '../../sql/companysetting.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import shapeSetting from './shapeSetting.js';
|
import shapeSetting from './shapeSetting.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -13,14 +13,14 @@ import shapeSetting from './shapeSetting.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = list(pool);
|
* const fn = list(pool);
|
||||||
* const settings = await fn(42, 1, { frontendOnly: true });
|
* const settings = await fn(42, { frontendOnly: true });
|
||||||
* // => [{ key, value, frontend }]
|
* // => [{ key, value, frontend }]
|
||||||
*/
|
*/
|
||||||
export default function list(pool) {
|
export default function list(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, { frontendOnly = false } = {}) => {
|
return async (googleAuthId, { frontendOnly = false } = {}) => {
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_BY_COMPANY_AND_KEY, UPSERT } from '../../sql/companysetting.js';
|
import { GET_BY_COMPANY_AND_KEY, UPSERT } from '../../sql/companysetting.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import shapeSetting from './shapeSetting.js';
|
import shapeSetting from './shapeSetting.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,13 +10,13 @@ import shapeSetting from './shapeSetting.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = set(pool);
|
* const fn = set(pool);
|
||||||
* const setting = await fn(42, 1, { key: 'theme', value: 'dark', frontend: true });
|
* const setting = await fn(42, { key: 'theme', value: 'dark', frontend: true });
|
||||||
* // => { key, value, frontend }
|
* // => { key, value, frontend }
|
||||||
*/
|
*/
|
||||||
export default function set(pool) {
|
export default function set(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, input = {}) => {
|
return async (googleAuthId, input = {}) => {
|
||||||
const key = input.key?.trim();
|
const key = input.key?.trim();
|
||||||
if (!key) {
|
if (!key) {
|
||||||
throw new Error('Invalid setting');
|
throw new Error('Invalid setting');
|
||||||
@@ -26,7 +26,7 @@ export default function set(pool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const frontend = Boolean(input.frontend);
|
const frontend = Boolean(input.frontend);
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
await pool
|
await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
35
src/store/companyuser/resolveSelectedCompanyAccess.js
Normal file
35
src/store/companyuser/resolveSelectedCompanyAccess.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { GET_BY_ID } from '../../sql/google_auth.js';
|
||||||
|
import resolveCompanyAccess from './resolveCompanyAccess.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the user's selected company and checks company membership.
|
||||||
|
* @param {object} pool
|
||||||
|
* @returns {(googleAuthId: number) => Promise<object>}
|
||||||
|
*/
|
||||||
|
export default function resolveSelectedCompanyAccess(pool) {
|
||||||
|
const access = resolveCompanyAccess(pool);
|
||||||
|
|
||||||
|
return async (googleAuthId) => {
|
||||||
|
if (!Number.isFinite(googleAuthId)) {
|
||||||
|
throw new Error('Not authorized');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await pool
|
||||||
|
.request()
|
||||||
|
.input('googleAuthId', googleAuthId)
|
||||||
|
.query(GET_BY_ID);
|
||||||
|
|
||||||
|
const row = result.recordset[0];
|
||||||
|
if (!row) {
|
||||||
|
throw new Error('Not authorized');
|
||||||
|
}
|
||||||
|
|
||||||
|
const companyId = row.selectedCompanyId;
|
||||||
|
if (companyId == null) {
|
||||||
|
throw new Error('No company selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = await access(googleAuthId, companyId);
|
||||||
|
return { companyId, ...ctx };
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { CREATE, GET_NEXT_SORT } from '../../sql/customergroup.js';
|
import { CREATE, GET_NEXT_SORT } from '../../sql/customergroup.js';
|
||||||
import { POS_GROUP_NAME, SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
import { POS_GROUP_NAME, SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
const RESERVED_NAMES = new Set([POS_GROUP_NAME, SUPPLIER_GROUP_NAME]);
|
const RESERVED_NAMES = new Set([POS_GROUP_NAME, SUPPLIER_GROUP_NAME]);
|
||||||
|
|
||||||
@@ -16,13 +16,13 @@ function shape(row) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = create(pool);
|
* const fn = create(pool);
|
||||||
* const group = await fn(42, 1, { name: 'Wholesale' });
|
* const group = await fn(42, { name: 'Wholesale' });
|
||||||
* // => { id, name, sort }
|
* // => { id, name, sort }
|
||||||
*/
|
*/
|
||||||
export default function create(pool) {
|
export default function create(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, { name } = {}) => {
|
return async (googleAuthId, { name } = {}) => {
|
||||||
const cleaned = name?.trim();
|
const cleaned = name?.trim();
|
||||||
if (!cleaned) {
|
if (!cleaned) {
|
||||||
throw new Error('Name required');
|
throw new Error('Name required');
|
||||||
@@ -31,7 +31,7 @@ export default function create(pool) {
|
|||||||
throw new Error('Name not allowed');
|
throw new Error('Name not allowed');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const next = await pool
|
const next = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELETE_BY_COMPANY_AND_ID } from '../../sql/customergroup.js';
|
import { DELETE_BY_COMPANY_AND_ID } from '../../sql/customergroup.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a customer group for a company by its id.
|
* Deletes a customer group for a company by its id.
|
||||||
@@ -9,17 +9,17 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = del(pool);
|
* const fn = del(pool);
|
||||||
* await fn(42, 1, 5);
|
* await fn(42, 5);
|
||||||
*/
|
*/
|
||||||
export default function del(pool) {
|
export default function del(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id) => {
|
return async (googleAuthId, id) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Customer group not found');
|
throw new Error('Customer group not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await pool
|
const result = await pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LIST_BY_COMPANY } from '../../sql/customergroup.js';
|
import { LIST_BY_COMPANY } from '../../sql/customergroup.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists the customer groups of a company.
|
* Lists the customer groups of a company.
|
||||||
@@ -9,14 +9,14 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = list(pool);
|
* const fn = list(pool);
|
||||||
* const groups = await fn(42, 1);
|
* const groups = await fn(42);
|
||||||
* // => [{ id, name, sort }]
|
* // => [{ id, name, sort }]
|
||||||
*/
|
*/
|
||||||
export default function list(pool) {
|
export default function list(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId) => {
|
return async (googleAuthId) => {
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
UPDATE_SORT,
|
UPDATE_SORT,
|
||||||
} from '../../sql/customergroup.js';
|
} from '../../sql/customergroup.js';
|
||||||
import request from '../request.js';
|
import request from '../request.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reorders the customer groups of a company.
|
* Reorders the customer groups of a company.
|
||||||
@@ -13,18 +13,18 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = order(pool);
|
* const fn = order(pool);
|
||||||
* const result = await fn(42, 1, { customergroupIds: [3, 1, 2] });
|
* const result = await fn(42, { customergroupIds: [3, 1, 2] });
|
||||||
* // => { customergroupIds: [3, 1, 2] }
|
* // => { customergroupIds: [3, 1, 2] }
|
||||||
*/
|
*/
|
||||||
export default function order(pool) {
|
export default function order(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, { customergroupIds } = {}) => {
|
return async (googleAuthId, { customergroupIds } = {}) => {
|
||||||
if (!Array.isArray(customergroupIds)) {
|
if (!Array.isArray(customergroupIds)) {
|
||||||
throw new Error('Invalid customer group order');
|
throw new Error('Invalid customer group order');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const groups = await pool
|
const groups = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { GET_BY_COMPANY_AND_ID, UPDATE } from '../../sql/customergroup.js';
|
import { GET_BY_COMPANY_AND_ID, UPDATE } from '../../sql/customergroup.js';
|
||||||
import { POS_GROUP_NAME, SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
import { POS_GROUP_NAME, SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
const LOCKED_NAMES = new Set([POS_GROUP_NAME, SUPPLIER_GROUP_NAME]);
|
const LOCKED_NAMES = new Set([POS_GROUP_NAME, SUPPLIER_GROUP_NAME]);
|
||||||
|
|
||||||
@@ -16,13 +16,13 @@ function shape(row) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = update(pool);
|
* const fn = update(pool);
|
||||||
* const group = await fn(42, 1, 5, { name: 'Retail' });
|
* const group = await fn(42, 5, { name: 'Retail' });
|
||||||
* // => { id, name, sort }
|
* // => { id, name, sort }
|
||||||
*/
|
*/
|
||||||
export default function update(pool) {
|
export default function update(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id, { name } = {}) => {
|
return async (googleAuthId, id, { name } = {}) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Customer group not found');
|
throw new Error('Customer group not found');
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ export default function update(pool) {
|
|||||||
throw new Error('Name required');
|
throw new Error('Name required');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const existing = await pool
|
const existing = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { CREATE_MANIFEST, DELIVERY_TYPE } from '../../sql/delivery.js';
|
import { CREATE_MANIFEST, DELIVERY_TYPE } from '../../sql/delivery.js';
|
||||||
import request from '../request.js';
|
import request from '../request.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import taxEnsure from '../tax/ensure.js';
|
import taxEnsure from '../tax/ensure.js';
|
||||||
import {
|
import {
|
||||||
loadDelivery,
|
loadDelivery,
|
||||||
@@ -17,14 +17,14 @@ import { assertSupplier, insertLines } from './writeLines.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = create(pool);
|
* const fn = create(pool);
|
||||||
* const delivery = await fn(42, 1, { number: 'D-1', date: '2026-01-01', supplierId: 5, lines: [...] });
|
* const delivery = await fn(42, { number: 'D-1', date: '2026-01-01', supplierId: 5, lines: [...] });
|
||||||
* // => { id, number, type, entityId, date, lines: [...] }
|
* // => { id, number, type, entityId, date, lines: [...] }
|
||||||
*/
|
*/
|
||||||
export default function create(pool) {
|
export default function create(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const ensureTax = taxEnsure(pool);
|
const ensureTax = taxEnsure(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, body = {}) => {
|
return async (googleAuthId, body = {}) => {
|
||||||
const number = body.number?.trim?.() ? body.number.trim() : null;
|
const number = body.number?.trim?.() ? body.number.trim() : null;
|
||||||
const date = parseDeliveryDate(body.date);
|
const date = parseDeliveryDate(body.date);
|
||||||
if (!number || !date) {
|
if (!number || !date) {
|
||||||
@@ -33,7 +33,7 @@ export default function create(pool) {
|
|||||||
|
|
||||||
const lines = normalizeLines(body.lines ?? []);
|
const lines = normalizeLines(body.lines ?? []);
|
||||||
|
|
||||||
const { rootCategoryId } = await access(googleAuthId, companyId);
|
const { companyId, rootCategoryId } = await access(googleAuthId);
|
||||||
|
|
||||||
const tx = pool.transaction();
|
const tx = pool.transaction();
|
||||||
await tx.begin();
|
await tx.begin();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELETE_MANIFEST, DELIVERY_TYPE } from '../../sql/delivery.js';
|
import { DELETE_MANIFEST, DELIVERY_TYPE } from '../../sql/delivery.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a delivery by its id within a company.
|
* Deletes a delivery by its id within a company.
|
||||||
@@ -9,17 +9,17 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = del(pool);
|
* const fn = del(pool);
|
||||||
* await fn(42, 1, 5);
|
* await fn(42, 5);
|
||||||
*/
|
*/
|
||||||
export default function del(pool) {
|
export default function del(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id) => {
|
return async (googleAuthId, id) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Delivery not found');
|
throw new Error('Delivery not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import { loadDelivery } from './helpers.js';
|
import { loadDelivery } from './helpers.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,18 +9,18 @@ import { loadDelivery } from './helpers.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = getById(pool);
|
* const fn = getById(pool);
|
||||||
* const delivery = await fn(42, 1, 5);
|
* const delivery = await fn(42, 5);
|
||||||
* // => { id, number, type, entityId, date, lines: [...] }
|
* // => { id, number, type, entityId, date, lines: [...] }
|
||||||
*/
|
*/
|
||||||
export default function getById(pool) {
|
export default function getById(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id) => {
|
return async (googleAuthId, id) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Delivery not found');
|
throw new Error('Delivery not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const delivery = await loadDelivery(pool, null, companyId, id);
|
const delivery = await loadDelivery(pool, null, companyId, id);
|
||||||
if (!delivery) {
|
if (!delivery) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELIVERY_TYPE, LIST_DELIVERIES } from '../../sql/delivery.js';
|
import { DELIVERY_TYPE, LIST_DELIVERIES } from '../../sql/delivery.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import { shapeSummary } from './helpers.js';
|
import { shapeSummary } from './helpers.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,14 +10,14 @@ import { shapeSummary } from './helpers.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = list(pool);
|
* const fn = list(pool);
|
||||||
* const deliveries = await fn(42, 1);
|
* const deliveries = await fn(42);
|
||||||
* // => [{ id, number, type, entityId, date }]
|
* // => [{ id, number, type, entityId, date }]
|
||||||
*/
|
*/
|
||||||
export default function list(pool) {
|
export default function list(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId) => {
|
return async (googleAuthId) => {
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
UPDATE_MANIFEST,
|
UPDATE_MANIFEST,
|
||||||
} from '../../sql/delivery.js';
|
} from '../../sql/delivery.js';
|
||||||
import request from '../request.js';
|
import request from '../request.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import taxEnsure from '../tax/ensure.js';
|
import taxEnsure from '../tax/ensure.js';
|
||||||
import {
|
import {
|
||||||
loadDelivery,
|
loadDelivery,
|
||||||
@@ -23,14 +23,14 @@ import { assertSupplier, insertLines } from './writeLines.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = update(pool);
|
* const fn = update(pool);
|
||||||
* const delivery = await fn(42, 1, 5, { number: 'D-2', lines: [...] });
|
* const delivery = await fn(42, 5, { number: 'D-2', lines: [...] });
|
||||||
* // => { id, number, type, entityId, date, lines: [...] }
|
* // => { id, number, type, entityId, date, lines: [...] }
|
||||||
*/
|
*/
|
||||||
export default function update(pool) {
|
export default function update(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const ensureTax = taxEnsure(pool);
|
const ensureTax = taxEnsure(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id, patch = {}) => {
|
return async (googleAuthId, id, patch = {}) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Delivery not found');
|
throw new Error('Delivery not found');
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ export default function update(pool) {
|
|||||||
normalizedLines = normalizeLines(patch.lines);
|
normalizedLines = normalizeLines(patch.lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { rootCategoryId } = await access(googleAuthId, companyId);
|
const { companyId, rootCategoryId } = await access(googleAuthId);
|
||||||
|
|
||||||
const tx = pool.transaction();
|
const tx = pool.transaction();
|
||||||
await tx.begin();
|
await tx.begin();
|
||||||
|
|||||||
@@ -1,40 +1,30 @@
|
|||||||
import { CREATE } from '../../sql/entity.js';
|
import { CREATE } from '../../sql/entity.js';
|
||||||
import { INSERT as INSERT_HISTORY } from '../../sql/entityhistory.js';
|
import { INSERT as INSERT_HISTORY } from '../../sql/entityhistory.js';
|
||||||
import request from '../request.js';
|
import request from '../request.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveCustomerGroupAccess from '../customergroup/resolveCustomerGroupAccess.js';
|
import resolveCustomerGroupAccess from '../customergroup/resolveCustomerGroupAccess.js';
|
||||||
|
import nextNumber from '../numbers/nextNumber.js';
|
||||||
function shape(row) {
|
import shape from './shape.js';
|
||||||
return {
|
|
||||||
id: row.id,
|
|
||||||
customergroupId: row.customergroupId,
|
|
||||||
firstName: row.firstName ?? null,
|
|
||||||
name: row.name,
|
|
||||||
createdAt: row.createdAt,
|
|
||||||
updatedAt: row.updatedAt,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new entity (customer) in a customer group, recording history.
|
* Creates a new entity (customer) in a customer group, recording history.
|
||||||
|
* Optional `number`; if omitted, allocates via `getnextnumberwithprefixandpadding`
|
||||||
|
* (`type` `entity`).
|
||||||
*
|
*
|
||||||
* @param {object} pool - The mssql connection pool.
|
* @param {object} pool - The mssql connection pool.
|
||||||
* @returns {Function} An async function that creates an entity.
|
* @returns {Function} An async function that creates an entity.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = create(pool);
|
* const fn = create(pool);
|
||||||
* const entity = await fn(42, 1, { customergroupId: 5, name: 'Doe', firstName: 'John' });
|
* const entity = await fn(42, { customergroupId: 5, name: 'Doe', firstName: 'John' });
|
||||||
* // => { id, customergroupId, firstName, name, createdAt, updatedAt }
|
* // => { id, customergroupId, firstName, name, number, createdAt, updatedAt }
|
||||||
*/
|
*/
|
||||||
export default function create(pool) {
|
export default function create(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const groupAccess = resolveCustomerGroupAccess(pool);
|
const groupAccess = resolveCustomerGroupAccess(pool);
|
||||||
|
const allocateNumber = nextNumber(pool);
|
||||||
|
|
||||||
return async (
|
return async (googleAuthId, { customergroupId, name, firstName = null, number } = {}) => {
|
||||||
googleAuthId,
|
|
||||||
companyId,
|
|
||||||
{ customergroupId, name, firstName = null } = {},
|
|
||||||
) => {
|
|
||||||
const cleaned = name?.trim();
|
const cleaned = name?.trim();
|
||||||
if (!cleaned) {
|
if (!cleaned) {
|
||||||
throw new Error('Name required');
|
throw new Error('Name required');
|
||||||
@@ -45,17 +35,26 @@ export default function create(pool) {
|
|||||||
? null
|
? null
|
||||||
: String(firstName).trim() || null;
|
: String(firstName).trim() || null;
|
||||||
|
|
||||||
const { companyuserId } = await access(googleAuthId, companyId);
|
const explicitNumber =
|
||||||
|
number == null || number === ''
|
||||||
|
? null
|
||||||
|
: String(number).trim() || null;
|
||||||
|
|
||||||
|
const { companyId, companyuserId } = await access(googleAuthId);
|
||||||
await groupAccess(companyId, customergroupId);
|
await groupAccess(companyId, customergroupId);
|
||||||
|
|
||||||
const tx = pool.transaction();
|
const tx = pool.transaction();
|
||||||
await tx.begin();
|
await tx.begin();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const entityNumber =
|
||||||
|
explicitNumber ?? (await allocateNumber(companyId, 'entity', tx));
|
||||||
|
|
||||||
const created = await request(pool, tx)
|
const created = await request(pool, tx)
|
||||||
.input('customergroupId', customergroupId)
|
.input('customergroupId', customergroupId)
|
||||||
.input('firstName', first)
|
.input('firstName', first)
|
||||||
.input('name', cleaned)
|
.input('name', cleaned)
|
||||||
|
.input('number', entityNumber)
|
||||||
.query(CREATE);
|
.query(CREATE);
|
||||||
|
|
||||||
const row = created.recordset[0];
|
const row = created.recordset[0];
|
||||||
@@ -74,6 +73,9 @@ export default function create(pool) {
|
|||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
if (err.number === 2601 || err.number === 2627) {
|
||||||
|
throw new Error('Number already in use');
|
||||||
|
}
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELETE_BY_COMPANY_AND_ID } from '../../sql/entity.js';
|
import { DELETE_BY_COMPANY_AND_ID } from '../../sql/entity.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes an entity by its id within a company.
|
* Deletes an entity by its id within a company.
|
||||||
@@ -9,17 +9,17 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = del(pool);
|
* const fn = del(pool);
|
||||||
* await fn(42, 1, 5);
|
* await fn(42, 5);
|
||||||
*/
|
*/
|
||||||
export default function del(pool) {
|
export default function del(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id) => {
|
return async (googleAuthId, id) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Entity not found');
|
throw new Error('Entity not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,16 +1,6 @@
|
|||||||
import { GET_BY_COMPANY_AND_ID } from '../../sql/entity.js';
|
import { GET_BY_COMPANY_AND_ID } from '../../sql/entity.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
import shape from './shape.js';
|
||||||
function shape(row) {
|
|
||||||
return {
|
|
||||||
id: row.id,
|
|
||||||
customergroupId: row.customergroupId,
|
|
||||||
firstName: row.firstName ?? null,
|
|
||||||
name: row.name,
|
|
||||||
createdAt: row.createdAt,
|
|
||||||
updatedAt: row.updatedAt,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a single entity by its id within a company.
|
* Returns a single entity by its id within a company.
|
||||||
@@ -20,18 +10,18 @@ function shape(row) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = getById(pool);
|
* const fn = getById(pool);
|
||||||
* const entity = await fn(42, 1, 5);
|
* const entity = await fn(42, 5);
|
||||||
* // => { id, customergroupId, firstName, name, createdAt, updatedAt }
|
* // => { id, customergroupId, firstName, name, number, createdAt, updatedAt }
|
||||||
*/
|
*/
|
||||||
export default function getById(pool) {
|
export default function getById(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id) => {
|
return async (googleAuthId, id) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Entity not found');
|
throw new Error('Entity not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
46
src/store/entity/isNumberFree.js
Normal file
46
src/store/entity/isNumberFree.js
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { NUMBER_TAKEN_IN_COMPANY } from '../../sql/entity.js';
|
||||||
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a customer number is free within the company.
|
||||||
|
* Pass `excludeEntityId` when editing so the entity's own number counts as free.
|
||||||
|
*
|
||||||
|
* @param {object} pool - The mssql connection pool.
|
||||||
|
* @returns {Function} An async function that checks number availability.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const fn = isNumberFree(pool);
|
||||||
|
* const free = await fn(42, 'C-100');
|
||||||
|
* // => true
|
||||||
|
* const freeOnEdit = await fn(42, 'C-100', { excludeEntityId: 5 });
|
||||||
|
* // => true
|
||||||
|
*/
|
||||||
|
export default function isNumberFree(pool) {
|
||||||
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
|
return async (googleAuthId, number, { excludeEntityId } = {}) => {
|
||||||
|
const cleaned =
|
||||||
|
number == null || number === '' ? null : String(number).trim() || null;
|
||||||
|
if (!cleaned) {
|
||||||
|
throw new Error('Number required');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
excludeEntityId != null &&
|
||||||
|
!Number.isFinite(excludeEntityId)
|
||||||
|
) {
|
||||||
|
throw new Error('Entity not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
|
const result = await pool
|
||||||
|
.request()
|
||||||
|
.input('companyId', companyId)
|
||||||
|
.input('number', cleaned)
|
||||||
|
.input('excludeEntityId', excludeEntityId ?? null)
|
||||||
|
.query(NUMBER_TAKEN_IN_COMPANY);
|
||||||
|
|
||||||
|
return !result.recordset[0];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,19 +5,9 @@ import {
|
|||||||
POS_GROUP_NAME,
|
POS_GROUP_NAME,
|
||||||
SUPPLIER_GROUP_NAME,
|
SUPPLIER_GROUP_NAME,
|
||||||
} from '../../sql/entity.js';
|
} from '../../sql/entity.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveCustomerGroupAccess from '../customergroup/resolveCustomerGroupAccess.js';
|
import resolveCustomerGroupAccess from '../customergroup/resolveCustomerGroupAccess.js';
|
||||||
|
import shape from './shape.js';
|
||||||
function shape(row) {
|
|
||||||
return {
|
|
||||||
id: row.id,
|
|
||||||
customergroupId: row.customergroupId,
|
|
||||||
firstName: row.firstName ?? null,
|
|
||||||
name: row.name,
|
|
||||||
createdAt: row.createdAt,
|
|
||||||
updatedAt: row.updatedAt,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists the entities (customers) of a company, optionally filtered by customer
|
* Lists the entities (customers) of a company, optionally filtered by customer
|
||||||
@@ -28,19 +18,15 @@ function shape(row) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = list(pool);
|
* const fn = list(pool);
|
||||||
* const entities = await fn(42, 1, { customergroupId: 5 });
|
* const entities = await fn(42, { customergroupId: 5 });
|
||||||
* // => [{ id, customergroupId, firstName, name, createdAt, updatedAt }]
|
* // => [{ id, customergroupId, firstName, name, number, createdAt, updatedAt }]
|
||||||
*/
|
*/
|
||||||
export default function list(pool) {
|
export default function list(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const groupAccess = resolveCustomerGroupAccess(pool);
|
const groupAccess = resolveCustomerGroupAccess(pool);
|
||||||
|
|
||||||
return async (
|
return async (googleAuthId, { customergroupId, role } = {}) => {
|
||||||
googleAuthId,
|
const { companyId } = await access(googleAuthId);
|
||||||
companyId,
|
|
||||||
{ customergroupId, role } = {},
|
|
||||||
) => {
|
|
||||||
await access(googleAuthId, companyId);
|
|
||||||
|
|
||||||
if (role != null && role !== 'customer') {
|
if (role != null && role !== 'customer') {
|
||||||
throw new Error('Invalid role');
|
throw new Error('Invalid role');
|
||||||
|
|||||||
24
src/store/entity/peekNextNumber.js
Normal file
24
src/store/entity/peekNextNumber.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
import peekNumber from '../numbers/peekNumber.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next customer number that would be allocated for the company
|
||||||
|
* (`numbers` type `entity`) without consuming it.
|
||||||
|
*
|
||||||
|
* @param {object} pool - The mssql connection pool.
|
||||||
|
* @returns {Function} An async function that peeks the next entity number.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const fn = peekNextNumber(pool);
|
||||||
|
* const number = await fn(42);
|
||||||
|
* // => '1'
|
||||||
|
*/
|
||||||
|
export default function peekNextNumber(pool) {
|
||||||
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
const peek = peekNumber(pool);
|
||||||
|
|
||||||
|
return async (googleAuthId) => {
|
||||||
|
const { companyId } = await access(googleAuthId);
|
||||||
|
return peek(companyId, 'entity');
|
||||||
|
};
|
||||||
|
}
|
||||||
11
src/store/entity/shape.js
Normal file
11
src/store/entity/shape.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export default function shape(row) {
|
||||||
|
return {
|
||||||
|
id: row.id,
|
||||||
|
customergroupId: row.customergroupId,
|
||||||
|
firstName: row.firstName ?? null,
|
||||||
|
name: row.name,
|
||||||
|
number: row.number ?? null,
|
||||||
|
createdAt: row.createdAt,
|
||||||
|
updatedAt: row.updatedAt,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,45 +1,37 @@
|
|||||||
import { GET_BY_COMPANY_AND_ID, UPDATE } from '../../sql/entity.js';
|
import { GET_BY_COMPANY_AND_ID, UPDATE } from '../../sql/entity.js';
|
||||||
import { INSERT as INSERT_HISTORY } from '../../sql/entityhistory.js';
|
import { INSERT as INSERT_HISTORY } from '../../sql/entityhistory.js';
|
||||||
import request from '../request.js';
|
import request from '../request.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
import shape from './shape.js';
|
||||||
function shape(row) {
|
|
||||||
return {
|
|
||||||
id: row.id,
|
|
||||||
customergroupId: row.customergroupId,
|
|
||||||
firstName: row.firstName ?? null,
|
|
||||||
name: row.name,
|
|
||||||
createdAt: row.createdAt,
|
|
||||||
updatedAt: row.updatedAt,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the name and/or first name of an entity, recording history.
|
* Updates name, first name, and/or customer number of an entity, recording history.
|
||||||
|
* Optional `number` sets the customer number explicitly (does not auto-allocate).
|
||||||
*
|
*
|
||||||
* @param {object} pool - The mssql connection pool.
|
* @param {object} pool - The mssql connection pool.
|
||||||
* @returns {Function} An async function that updates an entity.
|
* @returns {Function} An async function that updates an entity.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = update(pool);
|
* const fn = update(pool);
|
||||||
* const entity = await fn(42, 1, 5, { name: 'Doe', firstName: 'Jane' });
|
* const entity = await fn(42, 5, { name: 'Doe', firstName: 'Jane', number: 'C-42' });
|
||||||
* // => { id, customergroupId, firstName, name, createdAt, updatedAt }
|
* // => { id, customergroupId, firstName, name, number, createdAt, updatedAt }
|
||||||
*/
|
*/
|
||||||
export default function update(pool) {
|
export default function update(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id, patch = {}) => {
|
return async (googleAuthId, id, patch = {}) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Entity not found');
|
throw new Error('Entity not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasName = Object.prototype.hasOwnProperty.call(patch, 'name');
|
const hasName = Object.prototype.hasOwnProperty.call(patch, 'name');
|
||||||
const hasFirstName = Object.prototype.hasOwnProperty.call(patch, 'firstName');
|
const hasFirstName = Object.prototype.hasOwnProperty.call(patch, 'firstName');
|
||||||
if (!hasName && !hasFirstName) {
|
const hasNumber = Object.prototype.hasOwnProperty.call(patch, 'number');
|
||||||
|
if (!hasName && !hasFirstName && !hasNumber) {
|
||||||
throw new Error('Name required');
|
throw new Error('Name required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { companyuserId } = await access(googleAuthId, companyId);
|
const { companyId, companyuserId } = await access(googleAuthId);
|
||||||
|
|
||||||
const existing = await pool
|
const existing = await pool
|
||||||
.request()
|
.request()
|
||||||
@@ -68,6 +60,14 @@ export default function update(pool) {
|
|||||||
: String(patch.firstName).trim() || null;
|
: String(patch.firstName).trim() || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let number = current.number ?? null;
|
||||||
|
if (hasNumber) {
|
||||||
|
number =
|
||||||
|
patch.number == null || patch.number === ''
|
||||||
|
? null
|
||||||
|
: String(patch.number).trim() || null;
|
||||||
|
}
|
||||||
|
|
||||||
const historyLines = [];
|
const historyLines = [];
|
||||||
const oldFirst = current.firstName ?? '';
|
const oldFirst = current.firstName ?? '';
|
||||||
const newFirst = firstName ?? '';
|
const newFirst = firstName ?? '';
|
||||||
@@ -81,6 +81,13 @@ export default function update(pool) {
|
|||||||
`Name geändert von "${current.name}" auf "${name}"`,
|
`Name geändert von "${current.name}" auf "${name}"`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const oldNumber = current.number ?? '';
|
||||||
|
const newNumber = number ?? '';
|
||||||
|
if (oldNumber !== newNumber) {
|
||||||
|
historyLines.push(
|
||||||
|
`Nummer geändert von "${oldNumber}" auf "${newNumber}"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!historyLines.length) {
|
if (!historyLines.length) {
|
||||||
return shape(current);
|
return shape(current);
|
||||||
@@ -94,6 +101,7 @@ export default function update(pool) {
|
|||||||
.input('id', id)
|
.input('id', id)
|
||||||
.input('firstName', firstName)
|
.input('firstName', firstName)
|
||||||
.input('name', name)
|
.input('name', name)
|
||||||
|
.input('number', number)
|
||||||
.query(UPDATE);
|
.query(UPDATE);
|
||||||
|
|
||||||
const row = updated.recordset[0];
|
const row = updated.recordset[0];
|
||||||
@@ -115,6 +123,9 @@ export default function update(pool) {
|
|||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
if (err.number === 2601 || err.number === 2627) {
|
||||||
|
throw new Error('Number already in use');
|
||||||
|
}
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CREATE, GET_NEXT_SORT } from '../../sql/entityaddress.js';
|
import { CREATE, GET_NEXT_SORT } from '../../sql/entityaddress.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||||
|
|
||||||
function shape(row) {
|
function shape(row) {
|
||||||
@@ -32,14 +32,14 @@ function optionalString(value) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = create(pool);
|
* const fn = create(pool);
|
||||||
* const address = await fn(42, 1, 5, { addressType: 'billing', street: 'Main St', city: 'Berlin' });
|
* const address = await fn(42, 5, { addressType: 'billing', street: 'Main St', city: 'Berlin' });
|
||||||
* // => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }
|
* // => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }
|
||||||
*/
|
*/
|
||||||
export default function create(pool) {
|
export default function create(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const entityAccess = resolveEntityAccess(pool);
|
const entityAccess = resolveEntityAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, entityId, input = {}) => {
|
return async (googleAuthId, entityId, input = {}) => {
|
||||||
const addressType = input.addressType?.trim?.()
|
const addressType = input.addressType?.trim?.()
|
||||||
? input.addressType.trim()
|
? input.addressType.trim()
|
||||||
: null;
|
: null;
|
||||||
@@ -47,7 +47,7 @@ export default function create(pool) {
|
|||||||
throw new Error('Address type required');
|
throw new Error('Address type required');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
await entityAccess(companyId, entityId);
|
await entityAccess(companyId, entityId);
|
||||||
|
|
||||||
let sort = input.sort;
|
let sort = input.sort;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELETE_BY_ENTITY_AND_ID } from '../../sql/entityaddress.js';
|
import { DELETE_BY_ENTITY_AND_ID } from '../../sql/entityaddress.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,18 +10,18 @@ import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = del(pool);
|
* const fn = del(pool);
|
||||||
* await fn(42, 1, 5, 9);
|
* await fn(42, 5, 9);
|
||||||
*/
|
*/
|
||||||
export default function del(pool) {
|
export default function del(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const entityAccess = resolveEntityAccess(pool);
|
const entityAccess = resolveEntityAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, entityId, id) => {
|
return async (googleAuthId, entityId, id) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Address not found');
|
throw new Error('Address not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
await entityAccess(companyId, entityId);
|
await entityAccess(companyId, entityId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LIST_BY_ENTITY } from '../../sql/entityaddress.js';
|
import { LIST_BY_ENTITY } from '../../sql/entityaddress.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||||
|
|
||||||
function shape(row) {
|
function shape(row) {
|
||||||
@@ -26,15 +26,15 @@ function shape(row) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = list(pool);
|
* const fn = list(pool);
|
||||||
* const addresses = await fn(42, 1, 5);
|
* const addresses = await fn(42, 5);
|
||||||
* // => [{ id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }]
|
* // => [{ id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }]
|
||||||
*/
|
*/
|
||||||
export default function list(pool) {
|
export default function list(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const entityAccess = resolveEntityAccess(pool);
|
const entityAccess = resolveEntityAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, entityId) => {
|
return async (googleAuthId, entityId) => {
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
await entityAccess(companyId, entityId);
|
await entityAccess(companyId, entityId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_BY_ENTITY_AND_ID, UPDATE } from '../../sql/entityaddress.js';
|
import { GET_BY_ENTITY_AND_ID, UPDATE } from '../../sql/entityaddress.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||||
|
|
||||||
function shape(row) {
|
function shape(row) {
|
||||||
@@ -32,19 +32,19 @@ function optionalString(value) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = update(pool);
|
* const fn = update(pool);
|
||||||
* const address = await fn(42, 1, 5, 9, { city: 'Hamburg' });
|
* const address = await fn(42, 5, 9, { city: 'Hamburg' });
|
||||||
* // => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }
|
* // => { id, entityId, firstName, name, street, streetNumber, zip, city, county, addressType, sort }
|
||||||
*/
|
*/
|
||||||
export default function update(pool) {
|
export default function update(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const entityAccess = resolveEntityAccess(pool);
|
const entityAccess = resolveEntityAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, entityId, id, patch = {}) => {
|
return async (googleAuthId, entityId, id, patch = {}) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Address not found');
|
throw new Error('Address not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
await entityAccess(companyId, entityId);
|
await entityAccess(companyId, entityId);
|
||||||
|
|
||||||
const existing = await pool
|
const existing = await pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { CREATE, GET_NEXT_SORT } from '../../sql/entitycontact.js';
|
import { CREATE, GET_NEXT_SORT } from '../../sql/entitycontact.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||||
|
|
||||||
function shape(row) {
|
function shape(row) {
|
||||||
@@ -20,14 +20,14 @@ function shape(row) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = create(pool);
|
* const fn = create(pool);
|
||||||
* const contact = await fn(42, 1, 5, { contactType: 'email', contact: 'a@b.c' });
|
* const contact = await fn(42, 5, { contactType: 'email', contact: 'a@b.c' });
|
||||||
* // => { id, entityId, contactType, contact, sort }
|
* // => { id, entityId, contactType, contact, sort }
|
||||||
*/
|
*/
|
||||||
export default function create(pool) {
|
export default function create(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const entityAccess = resolveEntityAccess(pool);
|
const entityAccess = resolveEntityAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, entityId, input = {}) => {
|
return async (googleAuthId, entityId, input = {}) => {
|
||||||
const contactType = input.contactType?.trim?.()
|
const contactType = input.contactType?.trim?.()
|
||||||
? input.contactType.trim()
|
? input.contactType.trim()
|
||||||
: null;
|
: null;
|
||||||
@@ -36,7 +36,7 @@ export default function create(pool) {
|
|||||||
throw new Error('Contact required');
|
throw new Error('Contact required');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
await entityAccess(companyId, entityId);
|
await entityAccess(companyId, entityId);
|
||||||
|
|
||||||
let sort = input.sort;
|
let sort = input.sort;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELETE_BY_ENTITY_AND_ID } from '../../sql/entitycontact.js';
|
import { DELETE_BY_ENTITY_AND_ID } from '../../sql/entitycontact.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,18 +10,18 @@ import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = del(pool);
|
* const fn = del(pool);
|
||||||
* await fn(42, 1, 5, 9);
|
* await fn(42, 5, 9);
|
||||||
*/
|
*/
|
||||||
export default function del(pool) {
|
export default function del(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const entityAccess = resolveEntityAccess(pool);
|
const entityAccess = resolveEntityAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, entityId, id) => {
|
return async (googleAuthId, entityId, id) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Contact not found');
|
throw new Error('Contact not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
await entityAccess(companyId, entityId);
|
await entityAccess(companyId, entityId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LIST_BY_ENTITY } from '../../sql/entitycontact.js';
|
import { LIST_BY_ENTITY } from '../../sql/entitycontact.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||||
|
|
||||||
function shape(row) {
|
function shape(row) {
|
||||||
@@ -20,15 +20,15 @@ function shape(row) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = list(pool);
|
* const fn = list(pool);
|
||||||
* const contacts = await fn(42, 1, 5);
|
* const contacts = await fn(42, 5);
|
||||||
* // => [{ id, entityId, contactType, contact, sort }]
|
* // => [{ id, entityId, contactType, contact, sort }]
|
||||||
*/
|
*/
|
||||||
export default function list(pool) {
|
export default function list(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const entityAccess = resolveEntityAccess(pool);
|
const entityAccess = resolveEntityAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, entityId) => {
|
return async (googleAuthId, entityId) => {
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
await entityAccess(companyId, entityId);
|
await entityAccess(companyId, entityId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_BY_ENTITY_AND_ID, UPDATE } from '../../sql/entitycontact.js';
|
import { GET_BY_ENTITY_AND_ID, UPDATE } from '../../sql/entitycontact.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
import resolveEntityAccess from '../entity/resolveEntityAccess.js';
|
||||||
|
|
||||||
function shape(row) {
|
function shape(row) {
|
||||||
@@ -20,19 +20,19 @@ function shape(row) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = update(pool);
|
* const fn = update(pool);
|
||||||
* const contact = await fn(42, 1, 5, 9, { contact: 'b@c.d' });
|
* const contact = await fn(42, 5, 9, { contact: 'b@c.d' });
|
||||||
* // => { id, entityId, contactType, contact, sort }
|
* // => { id, entityId, contactType, contact, sort }
|
||||||
*/
|
*/
|
||||||
export default function update(pool) {
|
export default function update(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const entityAccess = resolveEntityAccess(pool);
|
const entityAccess = resolveEntityAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, entityId, id, patch = {}) => {
|
return async (googleAuthId, entityId, id, patch = {}) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Contact not found');
|
throw new Error('Contact not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
await entityAccess(companyId, entityId);
|
await entityAccess(companyId, entityId);
|
||||||
|
|
||||||
const existing = await pool
|
const existing = await pool
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
SUPPLIER_GROUP_NAME,
|
SUPPLIER_GROUP_NAME,
|
||||||
} from '../../sql/entity.js';
|
} from '../../sql/entity.js';
|
||||||
import request from '../request.js';
|
import request from '../request.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import taxEnsure from '../tax/ensure.js';
|
import taxEnsure from '../tax/ensure.js';
|
||||||
|
|
||||||
function shapeSummary(type, row) {
|
function shapeSummary(type, row) {
|
||||||
@@ -179,7 +179,7 @@ async function loadDoc(pool, tx, { type, companyId, id }) {
|
|||||||
* `label` → error prefix (`Quote` / `Order` → "Quote not found")
|
* `label` → error prefix (`Quote` / `Order` → "Quote not found")
|
||||||
*/
|
*/
|
||||||
export default function createManifestDocStore(pool, { type, label }) {
|
export default function createManifestDocStore(pool, { type, label }) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
const ensureTax = taxEnsure(pool);
|
const ensureTax = taxEnsure(pool);
|
||||||
const notFound = `${label} not found`;
|
const notFound = `${label} not found`;
|
||||||
const invalid = `Invalid ${label.toLowerCase()}`;
|
const invalid = `Invalid ${label.toLowerCase()}`;
|
||||||
@@ -188,11 +188,10 @@ export default function createManifestDocStore(pool, { type, label }) {
|
|||||||
* Lists the quote/order documents of a company.
|
* Lists the quote/order documents of a company.
|
||||||
*
|
*
|
||||||
* @param {number} googleAuthId - The Google auth user id.
|
* @param {number} googleAuthId - The Google auth user id.
|
||||||
* @param {number} companyId - The company id.
|
|
||||||
* @returns {Promise<Array<object>>} The document summaries.
|
* @returns {Promise<Array<object>>} The document summaries.
|
||||||
*/
|
*/
|
||||||
async function list(googleAuthId, companyId) {
|
async function list(googleAuthId) {
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
@@ -207,16 +206,15 @@ export default function createManifestDocStore(pool, { type, label }) {
|
|||||||
* Returns a single quote/order document by its id within a company.
|
* Returns a single quote/order document by its id within a company.
|
||||||
*
|
*
|
||||||
* @param {number} googleAuthId - The Google auth user id.
|
* @param {number} googleAuthId - The Google auth user id.
|
||||||
* @param {number} companyId - The company id.
|
|
||||||
* @param {number} id - The document id.
|
* @param {number} id - The document id.
|
||||||
* @returns {Promise<object|null>} The document with its lines, or null if not found.
|
* @returns {Promise<object|null>} The document with its lines, or null if not found.
|
||||||
*/
|
*/
|
||||||
async function getById(googleAuthId, companyId, id) {
|
async function getById(googleAuthId, id) {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error(notFound);
|
throw new Error(notFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const doc = await loadDoc(pool, null, { type, companyId, id });
|
const doc = await loadDoc(pool, null, { type, companyId, id });
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
@@ -229,11 +227,10 @@ export default function createManifestDocStore(pool, { type, label }) {
|
|||||||
* Creates a new quote/order document with its lines.
|
* Creates a new quote/order document with its lines.
|
||||||
*
|
*
|
||||||
* @param {number} googleAuthId - The Google auth user id.
|
* @param {number} googleAuthId - The Google auth user id.
|
||||||
* @param {number} companyId - The company id.
|
|
||||||
* @param {object} body - The document payload (`number`, `date`, `entityId`, `lines`).
|
* @param {object} body - The document payload (`number`, `date`, `entityId`, `lines`).
|
||||||
* @returns {Promise<object>} The created document with its lines.
|
* @returns {Promise<object>} The created document with its lines.
|
||||||
*/
|
*/
|
||||||
async function create(googleAuthId, companyId, body = {}) {
|
async function create(googleAuthId, body = {}) {
|
||||||
const number = body.number?.trim?.() ? body.number.trim() : null;
|
const number = body.number?.trim?.() ? body.number.trim() : null;
|
||||||
const date = parseDate(body.date);
|
const date = parseDate(body.date);
|
||||||
if (!number || !date) {
|
if (!number || !date) {
|
||||||
@@ -241,7 +238,7 @@ export default function createManifestDocStore(pool, { type, label }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const lines = normalizeLines(body.lines ?? []);
|
const lines = normalizeLines(body.lines ?? []);
|
||||||
const { rootCategoryId } = await access(googleAuthId, companyId);
|
const { companyId, rootCategoryId } = await access(googleAuthId);
|
||||||
|
|
||||||
const tx = pool.transaction();
|
const tx = pool.transaction();
|
||||||
await tx.begin();
|
await tx.begin();
|
||||||
@@ -288,12 +285,11 @@ export default function createManifestDocStore(pool, { type, label }) {
|
|||||||
* Updates a quote/order document's header and/or lines.
|
* Updates a quote/order document's header and/or lines.
|
||||||
*
|
*
|
||||||
* @param {number} googleAuthId - The Google auth user id.
|
* @param {number} googleAuthId - The Google auth user id.
|
||||||
* @param {number} companyId - The company id.
|
|
||||||
* @param {number} id - The document id.
|
* @param {number} id - The document id.
|
||||||
* @param {object} patch - The fields to update (`number`, `date`, `entityId`, `lines`).
|
* @param {object} patch - The fields to update (`number`, `date`, `entityId`, `lines`).
|
||||||
* @returns {Promise<object>} The updated document with its lines.
|
* @returns {Promise<object>} The updated document with its lines.
|
||||||
*/
|
*/
|
||||||
async function update(googleAuthId, companyId, id, patch = {}) {
|
async function update(googleAuthId, id, patch = {}) {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error(notFound);
|
throw new Error(notFound);
|
||||||
}
|
}
|
||||||
@@ -312,7 +308,7 @@ export default function createManifestDocStore(pool, { type, label }) {
|
|||||||
normalizedLines = normalizeLines(patch.lines);
|
normalizedLines = normalizeLines(patch.lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { rootCategoryId } = await access(googleAuthId, companyId);
|
const { companyId, rootCategoryId } = await access(googleAuthId);
|
||||||
|
|
||||||
const tx = pool.transaction();
|
const tx = pool.transaction();
|
||||||
await tx.begin();
|
await tx.begin();
|
||||||
@@ -396,16 +392,15 @@ export default function createManifestDocStore(pool, { type, label }) {
|
|||||||
* Deletes a quote/order document by its id within a company.
|
* Deletes a quote/order document by its id within a company.
|
||||||
*
|
*
|
||||||
* @param {number} googleAuthId - The Google auth user id.
|
* @param {number} googleAuthId - The Google auth user id.
|
||||||
* @param {number} companyId - The company id.
|
|
||||||
* @param {number} id - The document id.
|
* @param {number} id - The document id.
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function del(googleAuthId, companyId, id) {
|
async function del(googleAuthId, id) {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error(notFound);
|
throw new Error(notFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
19
src/store/numbers/nextNumber.js
Normal file
19
src/store/numbers/nextNumber.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { ENSURE_TYPE } from '../../sql/numbers.js';
|
||||||
|
import request from '../request.js';
|
||||||
|
|
||||||
|
export default function nextNumber(pool) {
|
||||||
|
return async (companyId, type, tx) => {
|
||||||
|
await request(pool, tx)
|
||||||
|
.input('companyId', companyId)
|
||||||
|
.input('type', type)
|
||||||
|
.query(ENSURE_TYPE);
|
||||||
|
|
||||||
|
const req = request(pool, tx);
|
||||||
|
req.input('company_id', companyId);
|
||||||
|
req.input('type', type);
|
||||||
|
req.output('value');
|
||||||
|
|
||||||
|
const result = await req.execute('getnextnumberwithprefixandpadding');
|
||||||
|
return result.output.value;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,21 +1,6 @@
|
|||||||
import { ENSURE_TYPE } from '../../sql/numbers.js';
|
import nextNumber from './nextNumber.js';
|
||||||
import request from '../request.js';
|
|
||||||
|
|
||||||
export default function nextSku(pool) {
|
export default function nextSku(pool) {
|
||||||
return async (companyId, tx) => {
|
const allocate = nextNumber(pool);
|
||||||
const type = 'sku';
|
return (companyId, tx) => allocate(companyId, 'sku', tx);
|
||||||
|
|
||||||
await request(pool, tx)
|
|
||||||
.input('companyId', companyId)
|
|
||||||
.input('type', type)
|
|
||||||
.query(ENSURE_TYPE);
|
|
||||||
|
|
||||||
const req = request(pool, tx);
|
|
||||||
req.input('company_id', companyId);
|
|
||||||
req.input('type', type);
|
|
||||||
req.output('value');
|
|
||||||
|
|
||||||
const result = await req.execute('getnextnumberwithprefixandpadding');
|
|
||||||
return result.output.value;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
19
src/store/numbers/peekNumber.js
Normal file
19
src/store/numbers/peekNumber.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { ENSURE_TYPE } from '../../sql/numbers.js';
|
||||||
|
import request from '../request.js';
|
||||||
|
|
||||||
|
export default function peekNumber(pool) {
|
||||||
|
return async (companyId, type, tx) => {
|
||||||
|
await request(pool, tx)
|
||||||
|
.input('companyId', companyId)
|
||||||
|
.input('type', type)
|
||||||
|
.query(ENSURE_TYPE);
|
||||||
|
|
||||||
|
const req = request(pool, tx);
|
||||||
|
req.input('company_id', companyId);
|
||||||
|
req.input('type', type);
|
||||||
|
req.output('value');
|
||||||
|
|
||||||
|
const result = await req.execute('peeknextnumberwithprefixandpadding');
|
||||||
|
return result.output.value;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import createManifestDocStore from '../manifestDoc/createStore.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const store = createOrderStore(pool);
|
* const store = createOrderStore(pool);
|
||||||
* const orders = await store.list(42, 1);
|
* const orders = await store.list(42);
|
||||||
* // => [{ id, number, type, entityId, date }]
|
* // => [{ id, number, type, entityId, date }]
|
||||||
*/
|
*/
|
||||||
export default function createOrderStore(pool) {
|
export default function createOrderStore(pool) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELETE_BY_COMPANY_AND_ID } from '../../sql/posterminal.js';
|
import { DELETE_BY_COMPANY_AND_ID } from '../../sql/posterminal.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a posterminal by its id within a company.
|
* Deletes a posterminal by its id within a company.
|
||||||
@@ -9,17 +9,17 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = del(pool);
|
* const fn = del(pool);
|
||||||
* await fn(42, 1, 5);
|
* await fn(42, 5);
|
||||||
*/
|
*/
|
||||||
export default function del(pool) {
|
export default function del(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id) => {
|
return async (googleAuthId, id) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Posterminal not found');
|
throw new Error('Posterminal not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LIST_BY_COMPANY } from '../../sql/posterminal.js';
|
import { LIST_BY_COMPANY } from '../../sql/posterminal.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists the posterminals of a company.
|
* Lists the posterminals of a company.
|
||||||
@@ -9,14 +9,14 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = list(pool);
|
* const fn = list(pool);
|
||||||
* const terminals = await fn(42, 1);
|
* const terminals = await fn(42);
|
||||||
* // => [{ id, name, token, pairingpin }]
|
* // => [{ id, name, token, pairingpin }]
|
||||||
*/
|
*/
|
||||||
export default function list(pool) {
|
export default function list(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId) => {
|
return async (googleAuthId) => {
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_BY_ID, SET_OFF, LIST_CATEGORY_IDS } from '../../sql/posterminal.js';
|
import { GET_BY_ID, SET_OFF, LIST_CATEGORY_IDS } from '../../sql/posterminal.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a category assignment from a posterminal (turns it off).
|
* Removes a category assignment from a posterminal (turns it off).
|
||||||
@@ -9,18 +9,18 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = setOff(pool);
|
* const fn = setOff(pool);
|
||||||
* const result = await fn(42, 1, 5, 9);
|
* const result = await fn(42, 5, 9);
|
||||||
* // => { id, categoryIds: [...] }
|
* // => { id, categoryIds: [...] }
|
||||||
*/
|
*/
|
||||||
export default function setOff(pool) {
|
export default function setOff(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, posterminalId, categoryId) => {
|
return async (googleAuthId, posterminalId, categoryId) => {
|
||||||
if (!Number.isFinite(posterminalId) || !Number.isFinite(categoryId)) {
|
if (!Number.isFinite(posterminalId) || !Number.isFinite(categoryId)) {
|
||||||
throw new Error('Invalid posterminal or category');
|
throw new Error('Invalid posterminal or category');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const existing = await pool
|
const existing = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_BY_ID, SET_OFF_ALL, LIST_CATEGORY_IDS } from '../../sql/posterminal.js';
|
import { GET_BY_ID, SET_OFF_ALL, LIST_CATEGORY_IDS } from '../../sql/posterminal.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all category assignments from a posterminal.
|
* Removes all category assignments from a posterminal.
|
||||||
@@ -9,18 +9,18 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = setOffAll(pool);
|
* const fn = setOffAll(pool);
|
||||||
* const result = await fn(42, 1, 5);
|
* const result = await fn(42, 5);
|
||||||
* // => { id, categoryIds: [] }
|
* // => { id, categoryIds: [] }
|
||||||
*/
|
*/
|
||||||
export default function setOffAll(pool) {
|
export default function setOffAll(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, posterminalId) => {
|
return async (googleAuthId, posterminalId) => {
|
||||||
if (!Number.isFinite(posterminalId)) {
|
if (!Number.isFinite(posterminalId)) {
|
||||||
throw new Error('Invalid posterminal');
|
throw new Error('Invalid posterminal');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
// Verify posterminal belongs to company
|
// Verify posterminal belongs to company
|
||||||
const pt = await pool
|
const pt = await pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_BY_ID, SET_ON, LIST_CATEGORY_IDS } from '../../sql/posterminal.js';
|
import { GET_BY_ID, SET_ON, LIST_CATEGORY_IDS } from '../../sql/posterminal.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns a category to a posterminal (turns it on for that category).
|
* Assigns a category to a posterminal (turns it on for that category).
|
||||||
@@ -9,18 +9,18 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = setOn(pool);
|
* const fn = setOn(pool);
|
||||||
* const result = await fn(42, 1, 5, 9);
|
* const result = await fn(42, 5, 9);
|
||||||
* // => { id, categoryIds: [9, ...] }
|
* // => { id, categoryIds: [9, ...] }
|
||||||
*/
|
*/
|
||||||
export default function setOn(pool) {
|
export default function setOn(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, posterminalId, categoryId) => {
|
return async (googleAuthId, posterminalId, categoryId) => {
|
||||||
if (!Number.isFinite(posterminalId) || !Number.isFinite(categoryId)) {
|
if (!Number.isFinite(posterminalId) || !Number.isFinite(categoryId)) {
|
||||||
throw new Error('Invalid posterminal or category');
|
throw new Error('Invalid posterminal or category');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const existing = await pool
|
const existing = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_BY_ID, SET_ON_ALL, LIST_CATEGORY_IDS } from '../../sql/posterminal.js';
|
import { GET_BY_ID, SET_ON_ALL, LIST_CATEGORY_IDS } from '../../sql/posterminal.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import { GET_COMPANY_ROOT_CATEGORY } from '../../sql/company.js';
|
import { GET_COMPANY_ROOT_CATEGORY } from '../../sql/company.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,18 +10,18 @@ import { GET_COMPANY_ROOT_CATEGORY } from '../../sql/company.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = setOnAll(pool);
|
* const fn = setOnAll(pool);
|
||||||
* const result = await fn(42, 1, 5);
|
* const result = await fn(42, 5);
|
||||||
* // => { id, categoryIds: [...] }
|
* // => { id, categoryIds: [...] }
|
||||||
*/
|
*/
|
||||||
export default function setOnAll(pool) {
|
export default function setOnAll(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, posterminalId) => {
|
return async (googleAuthId, posterminalId) => {
|
||||||
if (!Number.isFinite(posterminalId)) {
|
if (!Number.isFinite(posterminalId)) {
|
||||||
throw new Error('Invalid posterminal');
|
throw new Error('Invalid posterminal');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
// Verify posterminal belongs to company
|
// Verify posterminal belongs to company
|
||||||
const pt = await pool
|
const pt = await pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GET_BY_ID, CREATE, UPDATE } from '../../sql/posterminal.js';
|
import { GET_BY_ID, CREATE, UPDATE } from '../../sql/posterminal.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates or updates a posterminal for a company.
|
* Creates or updates a posterminal for a company.
|
||||||
@@ -9,13 +9,13 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = upsert(pool);
|
* const fn = upsert(pool);
|
||||||
* const terminal = await fn(42, 1, { name: 'Kasse 1', pairingpin: '1234', token: 'abc' });
|
* const terminal = await fn(42, { name: 'Kasse 1', pairingpin: '1234', token: 'abc' });
|
||||||
* // => { id, name, token, pairingpin }
|
* // => { id, name, token, pairingpin }
|
||||||
*/
|
*/
|
||||||
export default function upsert(pool) {
|
export default function upsert(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, input = {}) => {
|
return async (googleAuthId, input = {}) => {
|
||||||
const name = input.name?.trim();
|
const name = input.name?.trim();
|
||||||
if (!name) {
|
if (!name) {
|
||||||
throw new Error('Invalid posterminal');
|
throw new Error('Invalid posterminal');
|
||||||
@@ -27,7 +27,7 @@ export default function upsert(pool) {
|
|||||||
const token = input.token ?? null;
|
const token = input.token ?? null;
|
||||||
const id = input.id ?? null;
|
const id = input.id ?? null;
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
if (id) {
|
if (id) {
|
||||||
const existing = await pool
|
const existing = await pool
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import createManifestDocStore from '../manifestDoc/createStore.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const store = createQuoteStore(pool);
|
* const store = createQuoteStore(pool);
|
||||||
* const quotes = await store.list(42, 1);
|
* const quotes = await store.list(42);
|
||||||
* // => [{ id, number, type, entityId, date }]
|
* // => [{ id, number, type, entityId, date }]
|
||||||
*/
|
*/
|
||||||
export default function createQuoteStore(pool) {
|
export default function createQuoteStore(pool) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { CREATE } from '../../sql/entity.js';
|
import { CREATE } from '../../sql/entity.js';
|
||||||
import { INSERT as INSERT_HISTORY } from '../../sql/entityhistory.js';
|
import { INSERT as INSERT_HISTORY } from '../../sql/entityhistory.js';
|
||||||
import request from '../request.js';
|
import request from '../request.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import ensureLieferantenGroup from './ensureLieferantenGroup.js';
|
import ensureLieferantenGroup from './ensureLieferantenGroup.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -12,19 +12,19 @@ import ensureLieferantenGroup from './ensureLieferantenGroup.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = create(pool);
|
* const fn = create(pool);
|
||||||
* const supplier = await fn(42, 1, { name: 'Acme Supplies' });
|
* const supplier = await fn(42, { name: 'Acme Supplies' });
|
||||||
* // => { id, name, createdAt, updatedAt }
|
* // => { id, name, createdAt, updatedAt }
|
||||||
*/
|
*/
|
||||||
export default function create(pool) {
|
export default function create(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, { name } = {}) => {
|
return async (googleAuthId, { name } = {}) => {
|
||||||
const cleaned = name?.trim();
|
const cleaned = name?.trim();
|
||||||
if (!cleaned) {
|
if (!cleaned) {
|
||||||
throw new Error('Name required');
|
throw new Error('Name required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { companyuserId } = await access(googleAuthId, companyId);
|
const { companyId, companyuserId } = await access(googleAuthId);
|
||||||
|
|
||||||
const tx = pool.transaction();
|
const tx = pool.transaction();
|
||||||
await tx.begin();
|
await tx.begin();
|
||||||
@@ -36,6 +36,7 @@ export default function create(pool) {
|
|||||||
.input('customergroupId', customergroupId)
|
.input('customergroupId', customergroupId)
|
||||||
.input('firstName', null)
|
.input('firstName', null)
|
||||||
.input('name', cleaned)
|
.input('name', cleaned)
|
||||||
|
.input('number', null)
|
||||||
.query(CREATE);
|
.query(CREATE);
|
||||||
|
|
||||||
const row = created.recordset[0];
|
const row = created.recordset[0];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELETE_BY_ID, SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
import { DELETE_BY_ID, SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a supplier by its id within a company.
|
* Deletes a supplier by its id within a company.
|
||||||
@@ -9,17 +9,17 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = del(pool);
|
* const fn = del(pool);
|
||||||
* await fn(42, 1, 5);
|
* await fn(42, 5);
|
||||||
*/
|
*/
|
||||||
export default function del(pool) {
|
export default function del(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id) => {
|
return async (googleAuthId, id) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Supplier not found');
|
throw new Error('Supplier not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LIST_SUPPLIERS_BY_COMPANY, SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
import { LIST_SUPPLIERS_BY_COMPANY, SUPPLIER_GROUP_NAME } from '../../sql/entity.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists the suppliers of a company.
|
* Lists the suppliers of a company.
|
||||||
@@ -9,14 +9,14 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = list(pool);
|
* const fn = list(pool);
|
||||||
* const suppliers = await fn(42, 1);
|
* const suppliers = await fn(42);
|
||||||
* // => [{ id, name, createdAt, updatedAt }]
|
* // => [{ id, name, createdAt, updatedAt }]
|
||||||
*/
|
*/
|
||||||
export default function list(pool) {
|
export default function list(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId) => {
|
return async (googleAuthId) => {
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
} from '../../sql/entity.js';
|
} from '../../sql/entity.js';
|
||||||
import { INSERT as INSERT_HISTORY } from '../../sql/entityhistory.js';
|
import { INSERT as INSERT_HISTORY } from '../../sql/entityhistory.js';
|
||||||
import request from '../request.js';
|
import request from '../request.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
function shape(row) {
|
function shape(row) {
|
||||||
return {
|
return {
|
||||||
@@ -25,13 +25,13 @@ function shape(row) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = update(pool);
|
* const fn = update(pool);
|
||||||
* const supplier = await fn(42, 1, 5, { name: 'Acme GmbH' });
|
* const supplier = await fn(42, 5, { name: 'Acme GmbH' });
|
||||||
* // => { id, name, createdAt, updatedAt }
|
* // => { id, name, createdAt, updatedAt }
|
||||||
*/
|
*/
|
||||||
export default function update(pool) {
|
export default function update(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, id, { name } = {}) => {
|
return async (googleAuthId, id, { name } = {}) => {
|
||||||
if (!Number.isFinite(id)) {
|
if (!Number.isFinite(id)) {
|
||||||
throw new Error('Supplier not found');
|
throw new Error('Supplier not found');
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ export default function update(pool) {
|
|||||||
throw new Error('Name required');
|
throw new Error('Name required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { companyuserId } = await access(googleAuthId, companyId);
|
const { companyId, companyuserId } = await access(googleAuthId);
|
||||||
|
|
||||||
const existing = await pool
|
const existing = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DELETE_BY_COMPANY_AND_SI } from '../../sql/unit.js';
|
import { DELETE_BY_COMPANY_AND_SI } from '../../sql/unit.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a unit for a company by its SI code.
|
* Deletes a unit for a company by its SI code.
|
||||||
@@ -9,17 +9,17 @@ import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = del(pool);
|
* const fn = del(pool);
|
||||||
* await fn(42, 1, 'l');
|
* await fn(42, 'l');
|
||||||
*/
|
*/
|
||||||
export default function del(pool) {
|
export default function del(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, si) => {
|
return async (googleAuthId, si) => {
|
||||||
if (!si?.trim()) {
|
if (!si?.trim()) {
|
||||||
throw new Error('Unit not found');
|
throw new Error('Unit not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await access(googleAuthId, companyId);
|
const { companyId } = await access(googleAuthId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await pool
|
const result = await pool
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LIST_BY_COMPANY } from '../../sql/unit.js';
|
import { LIST_BY_COMPANY } from '../../sql/unit.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import shapeUnit from './shapeUnit.js';
|
import shapeUnit from './shapeUnit.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,14 +10,14 @@ import shapeUnit from './shapeUnit.js';
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = list(pool);
|
* const fn = list(pool);
|
||||||
* const units = await fn(42, 1);
|
* const units = await fn(42);
|
||||||
* // => [{ id, si, basesi, basesifactor, symbol, name }]
|
* // => [{ id, si, basesi, basesifactor, symbol, name }]
|
||||||
*/
|
*/
|
||||||
export default function list(pool) {
|
export default function list(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId) => {
|
return async (googleAuthId) => {
|
||||||
const { languageId } = await access(googleAuthId, companyId);
|
const { companyId, languageId } = await access(googleAuthId);
|
||||||
|
|
||||||
const result = await pool
|
const result = await pool
|
||||||
.request()
|
.request()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
GET_BY_UNIT_AND_LANGUAGE,
|
GET_BY_UNIT_AND_LANGUAGE,
|
||||||
UPDATE_BY_UNIT_AND_LANGUAGE,
|
UPDATE_BY_UNIT_AND_LANGUAGE,
|
||||||
} from '../../sql/unittext.js';
|
} from '../../sql/unittext.js';
|
||||||
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import request from '../request.js';
|
import request from '../request.js';
|
||||||
import shapeUnit from './shapeUnit.js';
|
import shapeUnit from './shapeUnit.js';
|
||||||
|
|
||||||
@@ -38,15 +38,15 @@ function validateUnit({ si, basesi, basesifactor, symbol, name }) {
|
|||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const fn = upsert(pool);
|
* const fn = upsert(pool);
|
||||||
* const unit = await fn(42, 1, { si: 'l', basesi: 'm3', basesifactor: 0.001, symbol: 'L', name: 'Liter' });
|
* const unit = await fn(42, { si: 'l', basesi: 'm3', basesifactor: 0.001, symbol: 'L', name: 'Liter' });
|
||||||
* // => { id, si, basesi, basesifactor, symbol, name }
|
* // => { id, si, basesi, basesifactor, symbol, name }
|
||||||
*/
|
*/
|
||||||
export default function upsert(pool) {
|
export default function upsert(pool) {
|
||||||
const access = resolveCompanyAccess(pool);
|
const access = resolveSelectedCompanyAccess(pool);
|
||||||
|
|
||||||
return async (googleAuthId, companyId, input) => {
|
return async (googleAuthId, input) => {
|
||||||
const unit = validateUnit(input);
|
const unit = validateUnit(input);
|
||||||
const { languageId } = await access(googleAuthId, companyId);
|
const { companyId, languageId } = await access(googleAuthId);
|
||||||
|
|
||||||
const tx = pool.transaction();
|
const tx = pool.transaction();
|
||||||
await tx.begin();
|
await tx.begin();
|
||||||
|
|||||||
Reference in New Issue
Block a user