u
This commit is contained in:
14
API.md
14
API.md
@@ -63,9 +63,9 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- **package**: `id PK, shipping_id->shipping, entityaddress_id->entityaddress, number:s(100), type:s(100), state:s(100), details?:txt`
|
- **package**: `id PK, shipping_id->shipping, entityaddress_id->entityaddress, number:s(100), type:s(100), state:s(100), details?:txt`
|
||||||
- **payment**: `id PK, account_id->account, manifest_id->manifest, type:s(100), amount:f`
|
- **payment**: `id PK, account_id->account, manifest_id->manifest, type:s(100), amount:f`
|
||||||
- **pic**: `id PK, w:i, h:i, size:bi, hash:s(64) UQ, thumbw:i, thumbh:i, thumbhash:s(64), source:txt, fullbinary:bin, thumbbinary:bin`
|
- **pic**: `id PK, w:i, h:i, size:bi, hash:s(64) UQ, thumbw:i, thumbh:i, thumbhash:s(64), source:txt, fullbinary:bin, thumbbinary:bin`
|
||||||
- **posterminal**: `id PK, company_id->company, name:s(255), token?:s(255) UQ, pairingpin?:s(50), root_category_id?->category, sync_root_articles:b=1, lastseen_at?:dt, updated_at:dt`
|
- **posterminal**: `id PK, company_id->company, name:s(255), token?:s(255) UQ, pairingpin?:s(50), maxknownobituaryid?:i, root_category_id?->category, sync_root_articles:b=1, lastseen_at?:dt, updated_at:dt`
|
||||||
- **posterminalcategory**: `id PK, posterminal_id->posterminal, category_id->category, UQ(posterminal_id, category_id)`
|
- **posterminalcategory**: `id PK, posterminal_id->posterminal, category_id->category, UQ(posterminal_id, category_id)`
|
||||||
- **posterminaltombstone**: `id PK, posterminal_id->posterminal, entity_type:s(50), entity_id:i, created_at:dt`
|
- **posterminalobituary**: `id PK, posterminal_id->posterminal, entity_type:s(50), entity_id:i, created_at:dt`
|
||||||
- **price**: `id PK, tax_id->tax, article_id->article, minmultiplier:d(18,4)=1, customergroup_id->customergroup, net:f`
|
- **price**: `id PK, tax_id->tax, article_id->article, minmultiplier:d(18,4)=1, customergroup_id->customergroup, net:f`
|
||||||
- **printer**: `id PK, company_id->company, address:s(255), type:s(50), model?:s(255), serial?:s(255), sort:i=0, desc?:txt`
|
- **printer**: `id PK, company_id->company, address:s(255), type:s(50), model?:s(255), serial?:s(255), sort:i=0, desc?:txt`
|
||||||
- **propertyname**: `id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)`
|
- **propertyname**: `id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)`
|
||||||
@@ -254,8 +254,8 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- `ship(provider: object): Function`
|
- `ship(provider: object): Function`
|
||||||
- [posterminal](API.posterminal.md)
|
- [posterminal](API.posterminal.md)
|
||||||
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
|
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
|
||||||
- `findByPairingpin(pairingpin: string, tx?: object): Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknowntombstoneid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>`
|
- `findByPairingpin(pairingpin: string, tx?: object): Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknownobituaryid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>`
|
||||||
- `findByToken(token: string, tx?: object): Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknowntombstoneid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>`
|
- `findByToken(token: string, tx?: object): Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknownobituaryid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>`
|
||||||
- `getCategoryCount(input: {posterminalId: number, cursor?: number}, tx?: object): Promise<number>`
|
- `getCategoryCount(input: {posterminalId: number, cursor?: number}, tx?: object): Promise<number>`
|
||||||
- `getCategoryList(input: {posterminalId: number, cursor?: number, limit?: number}, tx?: object): Promise<Array<object>>`
|
- `getCategoryList(input: {posterminalId: number, cursor?: number, limit?: number}, tx?: object): Promise<Array<object>>`
|
||||||
- `getCompositeProductCount(input: {posterminalId: number, cursor?: number}, tx?: object): Promise<number>`
|
- `getCompositeProductCount(input: {posterminalId: number, cursor?: number}, tx?: object): Promise<number>`
|
||||||
@@ -268,10 +268,10 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
|||||||
- `getMaxOrderIdCount(input: {posterminalId: number}, tx?: object): Promise<number>`
|
- `getMaxOrderIdCount(input: {posterminalId: number}, tx?: object): Promise<number>`
|
||||||
- `getProductCount(input: {posterminalId: number, cursor?: number}, tx?: object): Promise<number>`
|
- `getProductCount(input: {posterminalId: number, cursor?: number}, tx?: object): Promise<number>`
|
||||||
- `getProductList(input: {posterminalId: number, cursor?: number, limit?: number}, tx?: object): Promise<Array<object>>`
|
- `getProductList(input: {posterminalId: number, cursor?: number, limit?: number}, tx?: object): Promise<Array<object>>`
|
||||||
- `list(googleAuthId: number, tx?: object): Promise<Array<{id: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknowntombstoneid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}>>`
|
- `list(googleAuthId: number, tx?: object): Promise<Array<{id: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknownobituaryid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}>>`
|
||||||
- `pair(id: number, input: {token: string, clientserial?: string, pairedAt?: string}, tx?: object): Promise<{id: number, token: string, clientserial: string|null, pairedAt: string|null}>`
|
- `pair(id: number, input: {token: string, clientserial?: string, pairedAt?: string}, tx?: object): Promise<{id: number, token: string, clientserial: string|null, pairedAt: string|null}>`
|
||||||
- `recordTombstone(input: {companyId: number, entityType: string, entityId: number}, tx?: object): Promise<void>`
|
- `recordObituary(input: {companyId: number, entityType: string, entityId: number}, tx?: object): Promise<void>`
|
||||||
- `setMaxKnownTombstoneId(id: number, maxknowntombstoneid: number|null, tx?: object): Promise<{id: number, maxknowntombstoneid: number|null}>`
|
- `setMaxKnownObituaryId(id: number, maxknownobituaryid: number|null, tx?: object): Promise<{id: number, maxknownobituaryid: number|null}>`
|
||||||
- `setOff(googleAuthId: number, posterminalId: number, categoryId: number, tx?: object): Promise<{id: number, categoryIds: Array<number>}>`
|
- `setOff(googleAuthId: number, posterminalId: number, categoryId: number, tx?: object): Promise<{id: number, categoryIds: Array<number>}>`
|
||||||
- `setOffAll(googleAuthId: number, posterminalId: number, tx?: object): Promise<{id: number, categoryIds: Array<number>}>`
|
- `setOffAll(googleAuthId: number, posterminalId: number, tx?: object): Promise<{id: number, categoryIds: Array<number>}>`
|
||||||
- `setOn(googleAuthId: number, posterminalId: number, categoryId: number, tx?: object): Promise<{id: number, categoryIds: Array<number>}>`
|
- `setOn(googleAuthId: number, posterminalId: number, categoryId: number, tx?: object): Promise<{id: number, categoryIds: Array<number>}>`
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ Finds a posterminal by its pairingpin.
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknowntombstoneid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>` — The posterminal, or null if not found.
|
`Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknownobituaryid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>` — The posterminal, or null if not found.
|
||||||
|
|
||||||
## `posterminal.findByToken`
|
## `posterminal.findByToken`
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ Finds a posterminal by its auth token.
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknowntombstoneid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>` — The posterminal, or null if not found.
|
`Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknownobituaryid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>` — The posterminal, or null if not found.
|
||||||
|
|
||||||
## `posterminal.getCategoryCount`
|
## `posterminal.getCategoryCount`
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ Counts deleted entities for a POS terminal after the given cursor ID.
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `input` | `object` | |
|
| `input` | `object` | |
|
||||||
| `input.posterminalId` | `number` | The POS terminal id. |
|
| `input.posterminalId` | `number` | The POS terminal id. |
|
||||||
| `[input.cursor=0]` | `number` | The highest synced tombstone ID. |
|
| `[input.cursor=0]` | `number` | The highest synced obituary ID. |
|
||||||
| `[tx]` | `object` | Optional transaction. |
|
| `[tx]` | `object` | Optional transaction. |
|
||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
@@ -231,7 +231,7 @@ Lists deleted entities for a POS terminal after the given cursor ID.
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `input` | `object` | |
|
| `input` | `object` | |
|
||||||
| `input.posterminalId` | `number` | The POS terminal id. |
|
| `input.posterminalId` | `number` | The POS terminal id. |
|
||||||
| `[input.cursor=0]` | `number` | The highest synced tombstone ID. |
|
| `[input.cursor=0]` | `number` | The highest synced obituary ID. |
|
||||||
| `[input.limit=200]` | `number` | Max items to return. |
|
| `[input.limit=200]` | `number` | Max items to return. |
|
||||||
| `[tx]` | `object` | Optional transaction. |
|
| `[tx]` | `object` | Optional transaction. |
|
||||||
|
|
||||||
@@ -311,13 +311,13 @@ Lists the posterminals of the user's selected company.
|
|||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<Array<{id: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknowntombstoneid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}>>` — The posterminals.
|
`Promise<Array<{id: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknownobituaryid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}>>` — The posterminals.
|
||||||
|
|
||||||
**Example**
|
**Example**
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const terminals = await store.posterminal.list(42);
|
const terminals = await store.posterminal.list(42);
|
||||||
// => [{ id, name, token, pairingpin, pairedAt, clientserial, maxknowntombstoneid, rootCategoryId, syncRootArticles, lastseenAt, updatedAt }]
|
// => [{ id, name, token, pairingpin, pairedAt, clientserial, maxknownobituaryid, rootCategoryId, syncRootArticles, lastseenAt, updatedAt }]
|
||||||
```
|
```
|
||||||
|
|
||||||
## `posterminal.pair`
|
## `posterminal.pair`
|
||||||
@@ -341,11 +341,11 @@ Completes POS device pairing for a terminal.
|
|||||||
|
|
||||||
`Promise<{id: number, token: string, clientserial: string|null, pairedAt: string|null}>`
|
`Promise<{id: number, token: string, clientserial: string|null, pairedAt: string|null}>`
|
||||||
|
|
||||||
## `posterminal.recordTombstone`
|
## `posterminal.recordObituary`
|
||||||
|
|
||||||
*Source: `src/store/posterminal/recordTombstone.js`*
|
*Source: `src/store/posterminal/recordObituary.js`*
|
||||||
|
|
||||||
Records a tombstone for all active paired POS terminals of a company.
|
Records an obituary for all active paired POS terminals of a company.
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
@@ -361,23 +361,23 @@ Records a tombstone for all active paired POS terminals of a company.
|
|||||||
|
|
||||||
`Promise<void>`
|
`Promise<void>`
|
||||||
|
|
||||||
## `posterminal.setMaxKnownTombstoneId`
|
## `posterminal.setMaxKnownObituaryId`
|
||||||
|
|
||||||
*Source: `src/store/posterminal/setMaxKnownTombstoneId.js`*
|
*Source: `src/store/posterminal/setMaxKnownObituaryId.js`*
|
||||||
|
|
||||||
Updates the max known tombstone ID for a POS terminal.
|
Updates the max known obituary ID for a POS terminal.
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `id` | `number` | The posterminal id. |
|
| `id` | `number` | The posterminal id. |
|
||||||
| `maxknowntombstoneid` | `number|null` | The highest synced tombstone ID. |
|
| `maxknownobituaryid` | `number|null` | The highest synced obituary ID. |
|
||||||
| `[tx]` | `object` | Optional transaction to run within. |
|
| `[tx]` | `object` | Optional transaction to run within. |
|
||||||
|
|
||||||
**Returns**
|
**Returns**
|
||||||
|
|
||||||
`Promise<{id: number, maxknowntombstoneid: number|null}>`
|
`Promise<{id: number, maxknownobituaryid: number|null}>`
|
||||||
|
|
||||||
## `posterminal.setOff`
|
## `posterminal.setOff`
|
||||||
|
|
||||||
|
|||||||
@@ -379,9 +379,9 @@ const SCHEMA_TABLES = [
|
|||||||
['package', 'id PK, shipping_id->shipping, entityaddress_id->entityaddress, number:s(100), type:s(100), state:s(100), details?:txt'],
|
['package', 'id PK, shipping_id->shipping, entityaddress_id->entityaddress, number:s(100), type:s(100), state:s(100), details?:txt'],
|
||||||
['payment', 'id PK, account_id->account, manifest_id->manifest, type:s(100), amount:f'],
|
['payment', 'id PK, account_id->account, manifest_id->manifest, type:s(100), amount:f'],
|
||||||
['pic', 'id PK, w:i, h:i, size:bi, hash:s(64) UQ, thumbw:i, thumbh:i, thumbhash:s(64), source:txt, fullbinary:bin, thumbbinary:bin'],
|
['pic', 'id PK, w:i, h:i, size:bi, hash:s(64) UQ, thumbw:i, thumbh:i, thumbhash:s(64), source:txt, fullbinary:bin, thumbbinary:bin'],
|
||||||
['posterminal', 'id PK, company_id->company, name:s(255), token?:s(255) UQ, pairingpin?:s(50), root_category_id?->category, sync_root_articles:b=1, lastseen_at?:dt, updated_at:dt'],
|
['posterminal', 'id PK, company_id->company, name:s(255), token?:s(255) UQ, pairingpin?:s(50), maxknownobituaryid?:i, root_category_id?->category, sync_root_articles:b=1, lastseen_at?:dt, updated_at:dt'],
|
||||||
['posterminalcategory', 'id PK, posterminal_id->posterminal, category_id->category, UQ(posterminal_id, category_id)'],
|
['posterminalcategory', 'id PK, posterminal_id->posterminal, category_id->category, UQ(posterminal_id, category_id)'],
|
||||||
['posterminaltombstone', 'id PK, posterminal_id->posterminal, entity_type:s(50), entity_id:i, created_at:dt'],
|
['posterminalobituary', 'id PK, posterminal_id->posterminal, entity_type:s(50), entity_id:i, created_at:dt'],
|
||||||
['price', 'id PK, tax_id->tax, article_id->article, minmultiplier:d(18,4)=1, customergroup_id->customergroup, net:f'],
|
['price', 'id PK, tax_id->tax, article_id->article, minmultiplier:d(18,4)=1, customergroup_id->customergroup, net:f'],
|
||||||
['printer', 'id PK, company_id->company, address:s(255), type:s(50), model?:s(255), serial?:s(255), sort:i=0, desc?:txt'],
|
['printer', 'id PK, company_id->company, address:s(255), type:s(50), model?:s(255), serial?:s(255), sort:i=0, desc?:txt'],
|
||||||
['propertyname', 'id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)'],
|
['propertyname', 'id PK, company_id->company, name:s(255), sort:i=0, exclusive:b=0, UQ(company_id, name)'],
|
||||||
|
|||||||
@@ -170,8 +170,8 @@ function addInferredEdges(tables, edges) {
|
|||||||
const match = column.name.match(/^(.+)_id$/i);
|
const match = column.name.match(/^(.+)_id$/i);
|
||||||
if (!match) continue;
|
if (!match) continue;
|
||||||
|
|
||||||
// Tombstone tables store references to deleted entities, not active foreign keys.
|
// Obituary tables store references to deleted entities, not active foreign keys.
|
||||||
if (tableName.includes('tombstone')) continue;
|
if (tableName.includes('obituary') || tableName.includes('tombstone')) continue;
|
||||||
|
|
||||||
const candidate = match[1];
|
const candidate = match[1];
|
||||||
if (!tables.has(candidate) || candidate === tableName) continue;
|
if (!tables.has(candidate) || candidate === tableName) continue;
|
||||||
@@ -390,7 +390,7 @@ const CLUSTERS = [
|
|||||||
tables: ['tax', 'price', 'account', 'payment'],
|
tables: ['tax', 'price', 'account', 'payment'],
|
||||||
},
|
},
|
||||||
{ id: 'units', label: 'Units', tables: ['unit'] },
|
{ id: 'units', label: 'Units', tables: ['unit'] },
|
||||||
{ id: 'pos', label: 'POS', tables: ['posterminal', 'posterminalcategory', 'posterminaltombstone', 'printer', 'labeltemplate'] },
|
{ id: 'pos', label: 'POS', tables: ['posterminal', 'posterminalcategory', 'posterminalobituary', 'printer', 'labeltemplate'] },
|
||||||
{
|
{
|
||||||
id: 'ai',
|
id: 'ai',
|
||||||
label: 'AI & Models',
|
label: 'AI & Models',
|
||||||
|
|||||||
241
schema-graph.dot
241
schema-graph.dot
File diff suppressed because one or more lines are too long
6126
schema-graph.svg
6126
schema-graph.svg
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 407 KiB After Width: | Height: | Size: 408 KiB |
@@ -174,8 +174,8 @@ async function run() {
|
|||||||
() => store.article.getBySku(googleAuthId, artOnlySub.sku),
|
() => store.article.getBySku(googleAuthId, artOnlySub.sku),
|
||||||
/Article not found/
|
/Article not found/
|
||||||
);
|
);
|
||||||
// tombstone for artOnlySub exists
|
// obituary for artOnlySub exists
|
||||||
const t1 = provider.db.prepare("SELECT * FROM posterminaltombstone WHERE posterminal_id = ? AND entity_type = 'article' AND entity_id = ?").all(posTerminal.id, artOnlySub.id);
|
const t1 = provider.db.prepare("SELECT * FROM posterminalobituary WHERE posterminal_id = ? AND entity_type = 'article' AND entity_id = ?").all(posTerminal.id, artOnlySub.id);
|
||||||
assert.equal(t1.length, 1);
|
assert.equal(t1.length, 1);
|
||||||
|
|
||||||
// artParent and its child artChild: both deleted
|
// artParent and its child artChild: both deleted
|
||||||
@@ -187,8 +187,8 @@ async function run() {
|
|||||||
() => store.article.getBySku(googleAuthId, artChild.article.sku),
|
() => store.article.getBySku(googleAuthId, artChild.article.sku),
|
||||||
/Article not found/
|
/Article not found/
|
||||||
);
|
);
|
||||||
const tParent = provider.db.prepare("SELECT * FROM posterminaltombstone WHERE posterminal_id = ? AND entity_type = 'article' AND entity_id = ?").all(posTerminal.id, artParent.id);
|
const tParent = provider.db.prepare("SELECT * FROM posterminalobituary WHERE posterminal_id = ? AND entity_type = 'article' AND entity_id = ?").all(posTerminal.id, artParent.id);
|
||||||
const tChild = provider.db.prepare("SELECT * FROM posterminaltombstone WHERE posterminal_id = ? AND entity_type = 'article' AND entity_id = ?").all(posTerminal.id, artChild.article.id);
|
const tChild = provider.db.prepare("SELECT * FROM posterminalobituary WHERE posterminal_id = ? AND entity_type = 'article' AND entity_id = ?").all(posTerminal.id, artChild.article.id);
|
||||||
assert.equal(tParent.length, 1);
|
assert.equal(tParent.length, 1);
|
||||||
assert.equal(tChild.length, 1);
|
assert.equal(tChild.length, 1);
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import LibDashStore from '../src/index.js';
|
|||||||
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
console.log('--- Testing posterminaltombstone table and deletion flow ---');
|
console.log('--- Testing posterminalobituary table and deletion flow ---');
|
||||||
|
|
||||||
const tempDir = mkdtempSync(join(tmpdir(), 'test-tombstone-'));
|
const tempDir = mkdtempSync(join(tmpdir(), 'test-obituary-'));
|
||||||
const dbFile = join(tempDir, 'test.db');
|
const dbFile = join(tempDir, 'test.db');
|
||||||
const storageDir = join(tempDir, 'storage');
|
const storageDir = join(tempDir, 'storage');
|
||||||
|
|
||||||
@@ -21,11 +21,11 @@ async function run() {
|
|||||||
const store = await new LibDashStore(provider);
|
const store = await new LibDashStore(provider);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. Verify posterminaltombstone table exists and has expected columns
|
// 1. Verify posterminalobituary table exists and has expected columns
|
||||||
console.log('1. Checking posterminaltombstone schema...');
|
console.log('1. Checking posterminalobituary schema...');
|
||||||
const tableInfo = provider.db.pragma('table_info("posterminaltombstone")');
|
const tableInfo = provider.db.pragma('table_info("posterminalobituary")');
|
||||||
const colNames = tableInfo.map((c) => c.name);
|
const colNames = tableInfo.map((c) => c.name);
|
||||||
console.log('posterminaltombstone columns:', colNames);
|
console.log('posterminalobituary columns:', colNames);
|
||||||
assert.deepEqual(colNames, [
|
assert.deepEqual(colNames, [
|
||||||
'id',
|
'id',
|
||||||
'posterminal_id',
|
'posterminal_id',
|
||||||
@@ -36,9 +36,9 @@ async function run() {
|
|||||||
|
|
||||||
// Setup company first
|
// Setup company first
|
||||||
console.log('2. Setting up base data...');
|
console.log('2. Setting up base data...');
|
||||||
const googleAuthId = await store.google_auth.add('tombstone-tester@example.com');
|
const googleAuthId = await store.google_auth.add('obituary-tester@example.com');
|
||||||
const company = await store.company.create({
|
const company = await store.company.create({
|
||||||
name: 'Tombstone Corp',
|
name: 'Obituary Corp',
|
||||||
iso639: 'de',
|
iso639: 'de',
|
||||||
taxrate: 19,
|
taxrate: 19,
|
||||||
reducedtaxrate: 7,
|
reducedtaxrate: 7,
|
||||||
@@ -58,7 +58,7 @@ async function run() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 3. Test article deletion flow
|
// 3. Test article deletion flow
|
||||||
console.log('3. Testing article deletion tombstone...');
|
console.log('3. Testing article deletion obituary...');
|
||||||
const article = await store.article.createUnderParent({
|
const article = await store.article.createUnderParent({
|
||||||
googleAuthId,
|
googleAuthId,
|
||||||
parentId: company.rootCategoryId,
|
parentId: company.rootCategoryId,
|
||||||
@@ -67,7 +67,7 @@ async function run() {
|
|||||||
await store.article.delete(googleAuthId, article.sku);
|
await store.article.delete(googleAuthId, article.sku);
|
||||||
|
|
||||||
// 4. Test category deletion flow
|
// 4. Test category deletion flow
|
||||||
console.log('4. Testing category deletion tombstone...');
|
console.log('4. Testing category deletion obituary...');
|
||||||
const cat = await store.category.createUnderParent({
|
const cat = await store.category.createUnderParent({
|
||||||
googleAuthId,
|
googleAuthId,
|
||||||
parentId: company.rootCategoryId,
|
parentId: company.rootCategoryId,
|
||||||
@@ -76,7 +76,7 @@ async function run() {
|
|||||||
await store.category.delete({ googleAuthId, id: cat.id });
|
await store.category.delete({ googleAuthId, id: cat.id });
|
||||||
|
|
||||||
// 5. Test customer deletion flow
|
// 5. Test customer deletion flow
|
||||||
console.log('5. Testing customer deletion tombstone...');
|
console.log('5. Testing customer deletion obituary...');
|
||||||
const customer = await store.entity.create(googleAuthId, {
|
const customer = await store.entity.create(googleAuthId, {
|
||||||
name: 'Mustermann',
|
name: 'Mustermann',
|
||||||
firstName: 'Max',
|
firstName: 'Max',
|
||||||
@@ -85,31 +85,31 @@ async function run() {
|
|||||||
await store.entity.delete(googleAuthId, customer.id);
|
await store.entity.delete(googleAuthId, customer.id);
|
||||||
|
|
||||||
// 6. Test customer group deletion flow
|
// 6. Test customer group deletion flow
|
||||||
console.log('6. Testing customer group deletion tombstone...');
|
console.log('6. Testing customer group deletion obituary...');
|
||||||
const cg = await store.customergroup.create(googleAuthId, {
|
const cg = await store.customergroup.create(googleAuthId, {
|
||||||
name: 'VIP Guests',
|
name: 'VIP Guests',
|
||||||
});
|
});
|
||||||
await store.customergroup.delete(googleAuthId, cg.id);
|
await store.customergroup.delete(googleAuthId, cg.id);
|
||||||
|
|
||||||
// 7. Verify all tombstones exist in posterminaltombstone
|
// 7. Verify all obituaries exist in posterminalobituary
|
||||||
console.log('7. Verifying tombstones in database...');
|
console.log('7. Verifying obituaries in database...');
|
||||||
const allTombstones = provider.db
|
const allObituaries = provider.db
|
||||||
.prepare('SELECT * FROM posterminaltombstone WHERE posterminal_id = ? ORDER BY id ASC')
|
.prepare('SELECT * FROM posterminalobituary WHERE posterminal_id = ? ORDER BY id ASC')
|
||||||
.all(terminal.id);
|
.all(terminal.id);
|
||||||
console.log('Created tombstones:', allTombstones);
|
console.log('Created obituaries:', allObituaries);
|
||||||
assert.equal(allTombstones.length, 4);
|
assert.equal(allObituaries.length, 4);
|
||||||
|
|
||||||
assert.equal(allTombstones[0].entity_type, 'article');
|
assert.equal(allObituaries[0].entity_type, 'article');
|
||||||
assert.equal(allTombstones[0].entity_id, article.id);
|
assert.equal(allObituaries[0].entity_id, article.id);
|
||||||
|
|
||||||
assert.equal(allTombstones[1].entity_type, 'category');
|
assert.equal(allObituaries[1].entity_type, 'category');
|
||||||
assert.equal(allTombstones[1].entity_id, cat.id);
|
assert.equal(allObituaries[1].entity_id, cat.id);
|
||||||
|
|
||||||
assert.equal(allTombstones[2].entity_type, 'customer');
|
assert.equal(allObituaries[2].entity_type, 'customer');
|
||||||
assert.equal(allTombstones[2].entity_id, customer.id);
|
assert.equal(allObituaries[2].entity_id, customer.id);
|
||||||
|
|
||||||
assert.equal(allTombstones[3].entity_type, 'customergroup');
|
assert.equal(allObituaries[3].entity_type, 'customergroup');
|
||||||
assert.equal(allTombstones[3].entity_id, cg.id);
|
assert.equal(allObituaries[3].entity_id, cg.id);
|
||||||
|
|
||||||
// 8. Test getDeletedEntityCount & getDeletedEntityList APIs
|
// 8. Test getDeletedEntityCount & getDeletedEntityList APIs
|
||||||
console.log('8. Testing posterminal.getDeletedEntityCount & getDeletedEntityList...');
|
console.log('8. Testing posterminal.getDeletedEntityCount & getDeletedEntityList...');
|
||||||
@@ -132,7 +132,7 @@ async function run() {
|
|||||||
assert.equal(list[3].entityType, 'customergroup');
|
assert.equal(list[3].entityType, 'customergroup');
|
||||||
|
|
||||||
// Test cursor pagination
|
// Test cursor pagination
|
||||||
const cursor = allTombstones[1].id;
|
const cursor = allObituaries[1].id;
|
||||||
const countAfterCursor = await store.posterminal.getDeletedEntityCount({
|
const countAfterCursor = await store.posterminal.getDeletedEntityCount({
|
||||||
posterminalId: terminal.id,
|
posterminalId: terminal.id,
|
||||||
cursor,
|
cursor,
|
||||||
@@ -145,16 +145,16 @@ async function run() {
|
|||||||
limit: 10,
|
limit: 10,
|
||||||
});
|
});
|
||||||
assert.equal(listAfterCursor.length, 2);
|
assert.equal(listAfterCursor.length, 2);
|
||||||
assert.equal(listAfterCursor[0].id, allTombstones[2].id);
|
assert.equal(listAfterCursor[0].id, allObituaries[2].id);
|
||||||
assert.equal(listAfterCursor[1].id, allTombstones[3].id);
|
assert.equal(listAfterCursor[1].id, allObituaries[3].id);
|
||||||
|
|
||||||
// 9. Test maxknowntombstoneid
|
// 9. Test maxknownobituaryid
|
||||||
console.log('9. Testing maxknowntombstoneid...');
|
console.log('9. Testing maxknownobituaryid...');
|
||||||
await store.posterminal.setMaxKnownTombstoneId(terminal.id, allTombstones[3].id);
|
await store.posterminal.setMaxKnownObituaryId(terminal.id, allObituaries[3].id);
|
||||||
const updatedTerminal = await store.posterminal.findByToken('pos-token-123');
|
const updatedTerminal = await store.posterminal.findByToken('pos-token-123');
|
||||||
assert.equal(updatedTerminal.maxknowntombstoneid, allTombstones[3].id);
|
assert.equal(updatedTerminal.maxknownobituaryid, allObituaries[3].id);
|
||||||
|
|
||||||
// 10. Test setOff category & orphaned article tombstone generation
|
// 10. Test setOff category & orphaned article obituary generation
|
||||||
console.log('10. Testing setOff with orphaned and non-orphaned articles...');
|
console.log('10. Testing setOff with orphaned and non-orphaned articles...');
|
||||||
// Create Cat A and Cat B
|
// Create Cat A and Cat B
|
||||||
const catA = await store.category.createUnderParent({
|
const catA = await store.category.createUnderParent({
|
||||||
@@ -187,60 +187,60 @@ async function run() {
|
|||||||
await store.posterminal.setOn(googleAuthId, terminal.id, catA.id);
|
await store.posterminal.setOn(googleAuthId, terminal.id, catA.id);
|
||||||
await store.posterminal.setOn(googleAuthId, terminal.id, catB.id);
|
await store.posterminal.setOn(googleAuthId, terminal.id, catB.id);
|
||||||
|
|
||||||
// Clear previous tombstones to test cleanly
|
// Clear previous obituaries to test cleanly
|
||||||
provider.db.prepare('DELETE FROM posterminaltombstone WHERE posterminal_id = ?').run(terminal.id);
|
provider.db.prepare('DELETE FROM posterminalobituary WHERE posterminal_id = ?').run(terminal.id);
|
||||||
|
|
||||||
// Turn off Cat A:
|
// Turn off Cat A:
|
||||||
// - Cat A should get a tombstone
|
// - Cat A should get an obituary
|
||||||
// - Art A should get a tombstone (orphaned on this terminal)
|
// - Art A should get an obituary (orphaned on this terminal)
|
||||||
// - Art AB should NOT get a tombstone (still has active Cat B on this terminal)
|
// - Art AB should NOT get an obituary (still has active Cat B on this terminal)
|
||||||
await store.posterminal.setOff(googleAuthId, terminal.id, catA.id);
|
await store.posterminal.setOff(googleAuthId, terminal.id, catA.id);
|
||||||
|
|
||||||
const tombstonesAfterSetOff = provider.db
|
const obituariesAfterSetOff = provider.db
|
||||||
.prepare('SELECT entity_type, entity_id FROM posterminaltombstone WHERE posterminal_id = ? ORDER BY id ASC')
|
.prepare('SELECT entity_type, entity_id FROM posterminalobituary WHERE posterminal_id = ? ORDER BY id ASC')
|
||||||
.all(terminal.id);
|
.all(terminal.id);
|
||||||
|
|
||||||
console.log('Tombstones after setOff(Cat A):', tombstonesAfterSetOff);
|
console.log('Obituaries after setOff(Cat A):', obituariesAfterSetOff);
|
||||||
assert.equal(tombstonesAfterSetOff.length, 2);
|
assert.equal(obituariesAfterSetOff.length, 2);
|
||||||
assert.deepEqual(tombstonesAfterSetOff, [
|
assert.deepEqual(obituariesAfterSetOff, [
|
||||||
{ entity_type: 'category', entity_id: catA.id },
|
{ entity_type: 'category', entity_id: catA.id },
|
||||||
{ entity_type: 'article', entity_id: artA.id },
|
{ entity_type: 'article', entity_id: artA.id },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 11. Test setOn category clears pending tombstones for that category and its articles
|
// 11. Test setOn category clears pending obituaries for that category and its articles
|
||||||
console.log('11. Testing setOn clears pending category and article tombstones...');
|
console.log('11. Testing setOn clears pending category and article obituaries...');
|
||||||
await store.posterminal.setOn(googleAuthId, terminal.id, catA.id);
|
await store.posterminal.setOn(googleAuthId, terminal.id, catA.id);
|
||||||
const tombstonesAfterSetOn = provider.db
|
const obituariesAfterSetOn = provider.db
|
||||||
.prepare('SELECT entity_type, entity_id FROM posterminaltombstone WHERE posterminal_id = ?')
|
.prepare('SELECT entity_type, entity_id FROM posterminalobituary WHERE posterminal_id = ?')
|
||||||
.all(terminal.id);
|
.all(terminal.id);
|
||||||
console.log('Tombstones after setOn(Cat A):', tombstonesAfterSetOn);
|
console.log('Obituaries after setOn(Cat A):', obituariesAfterSetOn);
|
||||||
assert.equal(tombstonesAfterSetOn.length, 0);
|
assert.equal(obituariesAfterSetOn.length, 0);
|
||||||
|
|
||||||
// 12. Test setOffAll generates tombstones for all active categories and all their articles
|
// 12. Test setOffAll generates obituaries for all active categories and all their articles
|
||||||
console.log('12. Testing setOffAll tombstones...');
|
console.log('12. Testing setOffAll obituaries...');
|
||||||
await store.posterminal.setOffAll(googleAuthId, terminal.id);
|
await store.posterminal.setOffAll(googleAuthId, terminal.id);
|
||||||
const tombstonesAfterSetOffAll = provider.db
|
const obituariesAfterSetOffAll = provider.db
|
||||||
.prepare('SELECT entity_type, entity_id FROM posterminaltombstone WHERE posterminal_id = ? ORDER BY id ASC')
|
.prepare('SELECT entity_type, entity_id FROM posterminalobituary WHERE posterminal_id = ? ORDER BY id ASC')
|
||||||
.all(terminal.id);
|
.all(terminal.id);
|
||||||
console.log('Tombstones after setOffAll:', tombstonesAfterSetOffAll);
|
console.log('Obituaries after setOffAll:', obituariesAfterSetOffAll);
|
||||||
// Cat A, Cat B, Art A, Art AB
|
// Cat A, Cat B, Art A, Art AB
|
||||||
const catTombstones = tombstonesAfterSetOffAll.filter((t) => t.entity_type === 'category').map((t) => t.entity_id);
|
const catObituaries = obituariesAfterSetOffAll.filter((t) => t.entity_type === 'category').map((t) => t.entity_id);
|
||||||
const artTombstones = tombstonesAfterSetOffAll.filter((t) => t.entity_type === 'article').map((t) => t.entity_id);
|
const artObituaries = obituariesAfterSetOffAll.filter((t) => t.entity_type === 'article').map((t) => t.entity_id);
|
||||||
assert(catTombstones.includes(catA.id));
|
assert(catObituaries.includes(catA.id));
|
||||||
assert(catTombstones.includes(catB.id));
|
assert(catObituaries.includes(catB.id));
|
||||||
assert(artTombstones.includes(artA.id));
|
assert(artObituaries.includes(artA.id));
|
||||||
assert(artTombstones.includes(artAB.id));
|
assert(artObituaries.includes(artAB.id));
|
||||||
|
|
||||||
// 13. Test setOnAll clears category and article tombstones
|
// 13. Test setOnAll clears category and article obituaries
|
||||||
console.log('13. Testing setOnAll clears all category & article tombstones...');
|
console.log('13. Testing setOnAll clears all category & article obituaries...');
|
||||||
await store.posterminal.setOnAll(googleAuthId, terminal.id);
|
await store.posterminal.setOnAll(googleAuthId, terminal.id);
|
||||||
const tombstonesAfterSetOnAll = provider.db
|
const obituariesAfterSetOnAll = provider.db
|
||||||
.prepare('SELECT entity_type, entity_id FROM posterminaltombstone WHERE posterminal_id = ?')
|
.prepare('SELECT entity_type, entity_id FROM posterminalobituary WHERE posterminal_id = ?')
|
||||||
.all(terminal.id);
|
.all(terminal.id);
|
||||||
console.log('Tombstones after setOnAll:', tombstonesAfterSetOnAll);
|
console.log('Obituaries after setOnAll:', obituariesAfterSetOnAll);
|
||||||
assert.equal(tombstonesAfterSetOnAll.length, 0);
|
assert.equal(obituariesAfterSetOnAll.length, 0);
|
||||||
|
|
||||||
console.log('✅ ALL POSTERMINALTOMBSTONE TESTS PASSED');
|
console.log('✅ ALL POSTERMINALOBITUARY TESTS PASSED');
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
rmSync(tempDir, { recursive: true, force: true });
|
rmSync(tempDir, { recursive: true, force: true });
|
||||||
@@ -127,11 +127,11 @@ import posterminalGetCustomerGroupList from './store/posterminal/getCustomerGrou
|
|||||||
import posterminalGetCompositeProductCount from './store/posterminal/getCompositeProductCount.js';
|
import posterminalGetCompositeProductCount from './store/posterminal/getCompositeProductCount.js';
|
||||||
import posterminalGetDeletedEntityCount from './store/posterminal/getDeletedEntityCount.js';
|
import posterminalGetDeletedEntityCount from './store/posterminal/getDeletedEntityCount.js';
|
||||||
import posterminalGetDeletedEntityList from './store/posterminal/getDeletedEntityList.js';
|
import posterminalGetDeletedEntityList from './store/posterminal/getDeletedEntityList.js';
|
||||||
import posterminalRecordTombstone from './store/posterminal/recordTombstone.js';
|
import posterminalRecordObituary from './store/posterminal/recordObituary.js';
|
||||||
import posterminalGetMaxOrderIdCount from './store/posterminal/getMaxOrderIdCount.js';
|
import posterminalGetMaxOrderIdCount from './store/posterminal/getMaxOrderIdCount.js';
|
||||||
import posterminalGetCategoryList from './store/posterminal/getCategoryList.js';
|
import posterminalGetCategoryList from './store/posterminal/getCategoryList.js';
|
||||||
import posterminalGetProductList from './store/posterminal/getProductList.js';
|
import posterminalGetProductList from './store/posterminal/getProductList.js';
|
||||||
import posterminalSetMaxKnownTombstoneId from './store/posterminal/setMaxKnownTombstoneId.js';
|
import posterminalSetMaxKnownObituaryId from './store/posterminal/setMaxKnownObituaryId.js';
|
||||||
import posterminalTouchLastseen from './store/posterminal/touchLastseen.js';
|
import posterminalTouchLastseen from './store/posterminal/touchLastseen.js';
|
||||||
import langCreate from './store/lang/create.js';
|
import langCreate from './store/lang/create.js';
|
||||||
import langDelete from './store/lang/delete.js';
|
import langDelete from './store/lang/delete.js';
|
||||||
@@ -491,11 +491,11 @@ export default class LibDashStore {
|
|||||||
getCompositeProductCount: posterminalGetCompositeProductCount(provider),
|
getCompositeProductCount: posterminalGetCompositeProductCount(provider),
|
||||||
getDeletedEntityCount: posterminalGetDeletedEntityCount(provider),
|
getDeletedEntityCount: posterminalGetDeletedEntityCount(provider),
|
||||||
getDeletedEntityList: posterminalGetDeletedEntityList(provider),
|
getDeletedEntityList: posterminalGetDeletedEntityList(provider),
|
||||||
recordTombstone: posterminalRecordTombstone(provider),
|
recordObituary: posterminalRecordObituary(provider),
|
||||||
getMaxOrderIdCount: posterminalGetMaxOrderIdCount(provider),
|
getMaxOrderIdCount: posterminalGetMaxOrderIdCount(provider),
|
||||||
getCategoryList: posterminalGetCategoryList(provider),
|
getCategoryList: posterminalGetCategoryList(provider),
|
||||||
getProductList: posterminalGetProductList(provider),
|
getProductList: posterminalGetProductList(provider),
|
||||||
setMaxKnownTombstoneId: posterminalSetMaxKnownTombstoneId(provider),
|
setMaxKnownObituaryId: posterminalSetMaxKnownObituaryId(provider),
|
||||||
touchLastseen: posterminalTouchLastseen(provider),
|
touchLastseen: posterminalTouchLastseen(provider),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ SELECT
|
|||||||
pairingpin,
|
pairingpin,
|
||||||
paired_at AS pairedAt,
|
paired_at AS pairedAt,
|
||||||
clientserial AS clientserial,
|
clientserial AS clientserial,
|
||||||
maxknowntombstoneid AS maxknowntombstoneid,
|
maxknownobituaryid AS maxknownobituaryid,
|
||||||
root_category_id AS rootCategoryId,
|
root_category_id AS rootCategoryId,
|
||||||
sync_root_articles AS syncRootArticles,
|
sync_root_articles AS syncRootArticles,
|
||||||
lastseen_at AS lastseenAt,
|
lastseen_at AS lastseenAt,
|
||||||
@@ -25,7 +25,7 @@ SELECT
|
|||||||
pairingpin,
|
pairingpin,
|
||||||
paired_at AS pairedAt,
|
paired_at AS pairedAt,
|
||||||
clientserial AS clientserial,
|
clientserial AS clientserial,
|
||||||
maxknowntombstoneid AS maxknowntombstoneid,
|
maxknownobituaryid AS maxknownobituaryid,
|
||||||
root_category_id AS rootCategoryId,
|
root_category_id AS rootCategoryId,
|
||||||
sync_root_articles AS syncRootArticles,
|
sync_root_articles AS syncRootArticles,
|
||||||
lastseen_at AS lastseenAt,
|
lastseen_at AS lastseenAt,
|
||||||
@@ -43,7 +43,7 @@ SELECT
|
|||||||
pairingpin,
|
pairingpin,
|
||||||
paired_at AS pairedAt,
|
paired_at AS pairedAt,
|
||||||
clientserial AS clientserial,
|
clientserial AS clientserial,
|
||||||
maxknowntombstoneid AS maxknowntombstoneid,
|
maxknownobituaryid AS maxknownobituaryid,
|
||||||
root_category_id AS rootCategoryId,
|
root_category_id AS rootCategoryId,
|
||||||
sync_root_articles AS syncRootArticles,
|
sync_root_articles AS syncRootArticles,
|
||||||
lastseen_at AS lastseenAt,
|
lastseen_at AS lastseenAt,
|
||||||
@@ -59,14 +59,14 @@ WHERE id = @id
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const CREATE = `
|
export const CREATE = `
|
||||||
INSERT INTO posterminal (company_id, name, token, pairingpin, paired_at, clientserial, maxknowntombstoneid, root_category_id, sync_root_articles, lastseen_at, updated_at)
|
INSERT INTO posterminal (company_id, name, token, pairingpin, paired_at, clientserial, maxknownobituaryid, root_category_id, sync_root_articles, lastseen_at, updated_at)
|
||||||
OUTPUT INSERTED.id, INSERTED.name, INSERTED.token, INSERTED.pairingpin, INSERTED.paired_at AS pairedAt, INSERTED.clientserial AS clientserial, INSERTED.maxknowntombstoneid AS maxknowntombstoneid, INSERTED.root_category_id AS rootCategoryId, INSERTED.sync_root_articles AS syncRootArticles, INSERTED.lastseen_at AS lastseenAt, INSERTED.updated_at AS updatedAt
|
OUTPUT INSERTED.id, INSERTED.name, INSERTED.token, INSERTED.pairingpin, INSERTED.paired_at AS pairedAt, INSERTED.clientserial AS clientserial, INSERTED.maxknownobituaryid AS maxknownobituaryid, INSERTED.root_category_id AS rootCategoryId, INSERTED.sync_root_articles AS syncRootArticles, INSERTED.lastseen_at AS lastseenAt, INSERTED.updated_at AS updatedAt
|
||||||
VALUES (@companyId, @name, @token, @pairingpin, @pairedAt, @clientserial, @maxknowntombstoneid, @rootCategoryId, @syncRootArticles, @lastseenAt, SYSUTCDATETIME())
|
VALUES (@companyId, @name, @token, @pairingpin, @pairedAt, @clientserial, @maxknownobituaryid, @rootCategoryId, @syncRootArticles, @lastseenAt, SYSUTCDATETIME())
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const UPDATE = `
|
export const UPDATE = `
|
||||||
UPDATE posterminal
|
UPDATE posterminal
|
||||||
SET name = @name, token = @token, pairingpin = @pairingpin, paired_at = @pairedAt, clientserial = @clientserial, maxknowntombstoneid = @maxknowntombstoneid, root_category_id = @rootCategoryId, sync_root_articles = @syncRootArticles, lastseen_at = @lastseenAt, updated_at = SYSUTCDATETIME()
|
SET name = @name, token = @token, pairingpin = @pairingpin, paired_at = @pairedAt, clientserial = @clientserial, maxknownobituaryid = @maxknownobituaryid, root_category_id = @rootCategoryId, sync_root_articles = @syncRootArticles, lastseen_at = @lastseenAt, updated_at = SYSUTCDATETIME()
|
||||||
WHERE id = @id AND company_id = @companyId
|
WHERE id = @id AND company_id = @companyId
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -76,9 +76,9 @@ SET lastseen_at = SYSUTCDATETIME()
|
|||||||
WHERE id = @id
|
WHERE id = @id
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const SET_MAX_KNOWN_TOMBSTONE_ID = `
|
export const SET_MAX_KNOWN_OBITUARY_ID = `
|
||||||
UPDATE posterminal
|
UPDATE posterminal
|
||||||
SET maxknowntombstoneid = @maxknowntombstoneid
|
SET maxknownobituaryid = @maxknownobituaryid
|
||||||
WHERE id = @id
|
WHERE id = @id
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ SELECT
|
|||||||
pairingpin,
|
pairingpin,
|
||||||
paired_at AS pairedAt,
|
paired_at AS pairedAt,
|
||||||
clientserial AS clientserial,
|
clientserial AS clientserial,
|
||||||
maxknowntombstoneid AS maxknowntombstoneid,
|
maxknownobituaryid AS maxknownobituaryid,
|
||||||
root_category_id AS rootCategoryId,
|
root_category_id AS rootCategoryId,
|
||||||
sync_root_articles AS syncRootArticles,
|
sync_root_articles AS syncRootArticles,
|
||||||
lastseen_at AS lastseenAt,
|
lastseen_at AS lastseenAt,
|
||||||
@@ -483,8 +483,8 @@ WHERE pr.minmultiplier = 1
|
|||||||
GROUP BY pr.article_id, pr.customergroup_id
|
GROUP BY pr.article_id, pr.customergroup_id
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const RECORD_TOMBSTONE = `
|
export const RECORD_OBITUARY = `
|
||||||
INSERT INTO posterminaltombstone (posterminal_id, entity_type, entity_id)
|
INSERT INTO posterminalobituary (posterminal_id, entity_type, entity_id)
|
||||||
SELECT pt.id, @entityType, @entityId
|
SELECT pt.id, @entityType, @entityId
|
||||||
FROM posterminal pt
|
FROM posterminal pt
|
||||||
WHERE pt.company_id = @companyId AND pt.token IS NOT NULL
|
WHERE pt.company_id = @companyId AND pt.token IS NOT NULL
|
||||||
@@ -492,7 +492,7 @@ WHERE pt.company_id = @companyId AND pt.token IS NOT NULL
|
|||||||
|
|
||||||
export const COUNT_DELETED_ENTITIES = `
|
export const COUNT_DELETED_ENTITIES = `
|
||||||
SELECT COUNT(*) AS count
|
SELECT COUNT(*) AS count
|
||||||
FROM posterminaltombstone
|
FROM posterminalobituary
|
||||||
WHERE posterminal_id = @posterminalId AND id > @cursor
|
WHERE posterminal_id = @posterminalId AND id > @cursor
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -501,7 +501,7 @@ SELECT TOP (@limit)
|
|||||||
id,
|
id,
|
||||||
entity_type AS entityType,
|
entity_type AS entityType,
|
||||||
entity_id AS entityId
|
entity_id AS entityId
|
||||||
FROM posterminaltombstone
|
FROM posterminalobituary
|
||||||
WHERE posterminal_id = @posterminalId AND id > @cursor
|
WHERE posterminal_id = @posterminalId AND id > @cursor
|
||||||
ORDER BY id ASC
|
ORDER BY id ASC
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -392,20 +392,20 @@ BEGIN
|
|||||||
END
|
END
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const INIT_POSTERMINALTOMBSTONE = `
|
export const INIT_POSTERMINALOBITUARY = `
|
||||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'posterminaltombstone')
|
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'posterminalobituary')
|
||||||
BEGIN
|
BEGIN
|
||||||
CREATE TABLE posterminaltombstone (
|
CREATE TABLE posterminalobituary (
|
||||||
id INT IDENTITY(1,1) PRIMARY KEY,
|
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||||
posterminal_id INT NOT NULL,
|
posterminal_id INT NOT NULL,
|
||||||
entity_type NVARCHAR(50) NOT NULL,
|
entity_type NVARCHAR(50) NOT NULL,
|
||||||
entity_id INT NOT NULL,
|
entity_id INT NOT NULL,
|
||||||
created_at DATETIME2 NOT NULL CONSTRAINT DF_posterminaltombstone_created_at DEFAULT SYSUTCDATETIME(),
|
created_at DATETIME2 NOT NULL CONSTRAINT DF_posterminalobituary_created_at DEFAULT SYSUTCDATETIME(),
|
||||||
CONSTRAINT FK_posterminaltombstone_posterminal FOREIGN KEY (posterminal_id) REFERENCES posterminal(id) ON DELETE CASCADE
|
CONSTRAINT FK_posterminalobituary_posterminal FOREIGN KEY (posterminal_id) REFERENCES posterminal(id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX IX_posterminaltombstone_posterminal_id
|
CREATE INDEX IX_posterminalobituary_posterminal_id
|
||||||
ON posterminaltombstone (posterminal_id, id);
|
ON posterminalobituary (posterminal_id, id);
|
||||||
END
|
END
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -894,7 +894,7 @@ BEGIN
|
|||||||
pairingpin NVARCHAR(50) NULL,
|
pairingpin NVARCHAR(50) NULL,
|
||||||
paired_at DATETIME2 NULL,
|
paired_at DATETIME2 NULL,
|
||||||
clientserial NVARCHAR(255) NULL,
|
clientserial NVARCHAR(255) NULL,
|
||||||
maxknowntombstoneid INT NULL,
|
maxknownobituaryid INT NULL,
|
||||||
root_category_id INT NULL,
|
root_category_id INT NULL,
|
||||||
sync_root_articles BIT NOT NULL CONSTRAINT DF_posterminal_sync_root_articles DEFAULT 1,
|
sync_root_articles BIT NOT NULL CONSTRAINT DF_posterminal_sync_root_articles DEFAULT 1,
|
||||||
lastseen_at DATETIME2 NULL,
|
lastseen_at DATETIME2 NULL,
|
||||||
@@ -1503,7 +1503,7 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_COMPANYSETTING,
|
INIT_COMPANYSETTING,
|
||||||
INIT_POSTERMINAL,
|
INIT_POSTERMINAL,
|
||||||
INIT_POSTERMINALCATEGORY,
|
INIT_POSTERMINALCATEGORY,
|
||||||
INIT_POSTERMINALTOMBSTONE,
|
INIT_POSTERMINALOBITUARY,
|
||||||
INIT_PRINTER,
|
INIT_PRINTER,
|
||||||
INIT_LABELTEMPLATE,
|
INIT_LABELTEMPLATE,
|
||||||
INIT_FILE,
|
INIT_FILE,
|
||||||
|
|||||||
@@ -479,8 +479,8 @@ export class BetterSqlite3Provider extends BetterSqlite3Executor {
|
|||||||
if (posterminalCols.length > 0 && !posterminalCols.includes('clientserial')) {
|
if (posterminalCols.length > 0 && !posterminalCols.includes('clientserial')) {
|
||||||
this.db.exec(`ALTER TABLE posterminal ADD COLUMN clientserial TEXT`);
|
this.db.exec(`ALTER TABLE posterminal ADD COLUMN clientserial TEXT`);
|
||||||
}
|
}
|
||||||
if (posterminalCols.length > 0 && !posterminalCols.includes('maxknowntombstoneid')) {
|
if (posterminalCols.length > 0 && !posterminalCols.includes('maxknownobituaryid')) {
|
||||||
this.db.exec(`ALTER TABLE posterminal ADD COLUMN maxknowntombstoneid INTEGER`);
|
this.db.exec(`ALTER TABLE posterminal ADD COLUMN maxknownobituaryid INTEGER`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const propertynameCols = this.db.pragma('table_info("propertyname")').map((c) => c.name);
|
const propertynameCols = this.db.pragma('table_info("propertyname")').map((c) => c.name);
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ const queries = translateQueries(source, 'posterminal');
|
|||||||
export const {
|
export const {
|
||||||
CREATE, DELETE_BY_COMPANY_AND_ID, GET_BY_ID, LIST_BY_COMPANY,
|
CREATE, DELETE_BY_COMPANY_AND_ID, GET_BY_ID, LIST_BY_COMPANY,
|
||||||
LIST_CATEGORY_IDS, POSTERMINAL_IDS_BY_COMPANY, SET_OFF, SET_OFF_ALL, UPDATE,
|
LIST_CATEGORY_IDS, POSTERMINAL_IDS_BY_COMPANY, SET_OFF, SET_OFF_ALL, UPDATE,
|
||||||
FIND_BY_PAIRINGPIN, PAIR, SET_MAX_KNOWN_TOMBSTONE_ID,
|
FIND_BY_PAIRINGPIN, PAIR, SET_MAX_KNOWN_OBITUARY_ID,
|
||||||
FIND_BY_TOKEN, COUNT_PRODUCTS, COUNT_CATEGORIES, COUNT_CUSTOMERS,
|
FIND_BY_TOKEN, COUNT_PRODUCTS, COUNT_CATEGORIES, COUNT_CUSTOMERS,
|
||||||
COUNT_CUSTOMER_GROUPS, COUNT_COMPOSITE_PRODUCTS, MAX_ORDER_ID,
|
COUNT_CUSTOMER_GROUPS, COUNT_COMPOSITE_PRODUCTS, MAX_ORDER_ID,
|
||||||
LIST_POS_PRODUCT_CATEGORIES, LIST_POS_CUSTOMER_GROUP_IDS, LIST_POS_PRODUCT_PRICES,
|
LIST_POS_PRODUCT_CATEGORIES, LIST_POS_CUSTOMER_GROUP_IDS, LIST_POS_PRODUCT_PRICES,
|
||||||
TOUCH_LASTSEEN, RECORD_TOMBSTONE, COUNT_DELETED_ENTITIES,
|
TOUCH_LASTSEEN, RECORD_OBITUARY, COUNT_DELETED_ENTITIES,
|
||||||
} = queries;
|
} = queries;
|
||||||
|
|
||||||
export const SET_ON = `
|
export const SET_ON = `
|
||||||
@@ -269,7 +269,7 @@ SELECT
|
|||||||
id,
|
id,
|
||||||
entity_type AS entityType,
|
entity_type AS entityType,
|
||||||
entity_id AS entityId
|
entity_id AS entityId
|
||||||
FROM posterminaltombstone
|
FROM posterminalobituary
|
||||||
WHERE posterminal_id = @posterminalId AND id > @cursor
|
WHERE posterminal_id = @posterminalId AND id > @cursor
|
||||||
ORDER BY id ASC
|
ORDER BY id ASC
|
||||||
LIMIT @limit
|
LIMIT @limit
|
||||||
|
|||||||
@@ -608,7 +608,7 @@ CREATE TABLE IF NOT EXISTS posterminal (
|
|||||||
pairingpin TEXT,
|
pairingpin TEXT,
|
||||||
paired_at TEXT,
|
paired_at TEXT,
|
||||||
clientserial TEXT,
|
clientserial TEXT,
|
||||||
maxknowntombstoneid INTEGER,
|
maxknownobituaryid INTEGER,
|
||||||
root_category_id INTEGER,
|
root_category_id INTEGER,
|
||||||
sync_root_articles INTEGER NOT NULL DEFAULT 1,
|
sync_root_articles INTEGER NOT NULL DEFAULT 1,
|
||||||
lastseen_at TEXT,
|
lastseen_at TEXT,
|
||||||
@@ -631,8 +631,8 @@ CREATE TABLE IF NOT EXISTS posterminalcategory (
|
|||||||
);
|
);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const INIT_POSTERMINALTOMBSTONE = `
|
export const INIT_POSTERMINALOBITUARY = `
|
||||||
CREATE TABLE IF NOT EXISTS posterminaltombstone (
|
CREATE TABLE IF NOT EXISTS posterminalobituary (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
posterminal_id INTEGER NOT NULL,
|
posterminal_id INTEGER NOT NULL,
|
||||||
entity_type TEXT NOT NULL,
|
entity_type TEXT NOT NULL,
|
||||||
@@ -640,8 +640,8 @@ CREATE TABLE IF NOT EXISTS posterminaltombstone (
|
|||||||
created_at TEXT NOT NULL DEFAULT (${UTC_NOW}),
|
created_at TEXT NOT NULL DEFAULT (${UTC_NOW}),
|
||||||
FOREIGN KEY (posterminal_id) REFERENCES posterminal(id) ON DELETE CASCADE
|
FOREIGN KEY (posterminal_id) REFERENCES posterminal(id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS IX_posterminaltombstone_posterminal_id
|
CREATE INDEX IF NOT EXISTS IX_posterminalobituary_posterminal_id
|
||||||
ON posterminaltombstone (posterminal_id, id);
|
ON posterminalobituary (posterminal_id, id);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const INIT_PRINTER = `
|
export const INIT_PRINTER = `
|
||||||
@@ -1119,7 +1119,7 @@ export const SCHEMA_SCRIPTS = [
|
|||||||
INIT_COMPANYSETTING,
|
INIT_COMPANYSETTING,
|
||||||
INIT_POSTERMINAL,
|
INIT_POSTERMINAL,
|
||||||
INIT_POSTERMINALCATEGORY,
|
INIT_POSTERMINALCATEGORY,
|
||||||
INIT_POSTERMINALTOMBSTONE,
|
INIT_POSTERMINALOBITUARY,
|
||||||
INIT_PRINTER,
|
INIT_PRINTER,
|
||||||
INIT_LABELTEMPLATE,
|
INIT_LABELTEMPLATE,
|
||||||
INIT_FILE,
|
INIT_FILE,
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ import * as sqliteQueries from '../../providers/sqlite3/queries/articleDelete.js
|
|||||||
import * as mssqlArticle from '../../providers/mssql/queries/article.js';
|
import * as mssqlArticle from '../../providers/mssql/queries/article.js';
|
||||||
import * as sqliteArticle from '../../providers/sqlite3/queries/article.js';
|
import * as sqliteArticle from '../../providers/sqlite3/queries/article.js';
|
||||||
import resolveArticleBySku from './resolveArticleBySku.js';
|
import resolveArticleBySku from './resolveArticleBySku.js';
|
||||||
import recordTombstone from '../posterminal/recordTombstone.js';
|
import recordObituary from '../posterminal/recordObituary.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
export default function del(provider) {
|
export default function del(provider) {
|
||||||
const resolve = resolveArticleBySku(provider);
|
const resolve = resolveArticleBySku(provider);
|
||||||
const tombstone = recordTombstone(provider);
|
const recordObit = recordObituary(provider);
|
||||||
const isSqlite = provider?.dialect === 'sqlite3';
|
const isSqlite = provider?.dialect === 'sqlite3';
|
||||||
const queries = isSqlite ? sqliteQueries : mssqlQueries;
|
const queries = isSqlite ? sqliteQueries : mssqlQueries;
|
||||||
const articleQueries = isSqlite ? sqliteArticle : mssqlArticle;
|
const articleQueries = isSqlite ? sqliteArticle : mssqlArticle;
|
||||||
@@ -45,7 +45,7 @@ export default function del(provider) {
|
|||||||
const listIds = await runner.query(queries.GET_LIST_IDS, { articleId: id });
|
const listIds = await runner.query(queries.GET_LIST_IDS, { articleId: id });
|
||||||
const { articlelistId, optionslistId } = listIds.rows[0] ?? {};
|
const { articlelistId, optionslistId } = listIds.rows[0] ?? {};
|
||||||
|
|
||||||
await tombstone({ companyId, entityType: 'article', entityId: id }, runner);
|
await recordObit({ companyId, entityType: 'article', entityId: id }, runner);
|
||||||
|
|
||||||
await runner.query(queries.DELETE_PICS_BY_ARTICLE, { articleId: id });
|
await runner.query(queries.DELETE_PICS_BY_ARTICLE, { articleId: id });
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import * as sqliteArticleDelete from '../../providers/sqlite3/queries/articleDel
|
|||||||
import * as mssqlArticle from '../../providers/mssql/queries/article.js';
|
import * as mssqlArticle from '../../providers/mssql/queries/article.js';
|
||||||
import * as sqliteArticle from '../../providers/sqlite3/queries/article.js';
|
import * as sqliteArticle from '../../providers/sqlite3/queries/article.js';
|
||||||
import resolveCategoryAccess from './resolveCategoryAccess.js';
|
import resolveCategoryAccess from './resolveCategoryAccess.js';
|
||||||
import recordTombstone from '../posterminal/recordTombstone.js';
|
import recordObituary from '../posterminal/recordObituary.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
export default function del(provider) {
|
export default function del(provider) {
|
||||||
const access = resolveCategoryAccess(provider);
|
const access = resolveCategoryAccess(provider);
|
||||||
const tombstone = recordTombstone(provider);
|
const recordObit = recordObituary(provider);
|
||||||
const isSqlite = provider?.dialect === 'sqlite3';
|
const isSqlite = provider?.dialect === 'sqlite3';
|
||||||
const sql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
|
const sql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
|
||||||
const articleDeleteQueries = isSqlite ? sqliteArticleDelete : mssqlArticleDelete;
|
const articleDeleteQueries = isSqlite ? sqliteArticleDelete : mssqlArticleDelete;
|
||||||
@@ -67,7 +67,7 @@ export default function del(provider) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await runner.query(sql, { id });
|
await runner.query(sql, { id });
|
||||||
await tombstone({ companyId, entityType: 'category', entityId: id }, runner);
|
await recordObit({ companyId, entityType: 'category', entityId: id }, runner);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (
|
if (
|
||||||
err.message?.includes('FOREIGN KEY constraint failed') ||
|
err.message?.includes('FOREIGN KEY constraint failed') ||
|
||||||
@@ -149,7 +149,7 @@ export default function del(provider) {
|
|||||||
const listIds = await runner.query(articleDeleteQueries.GET_LIST_IDS, { articleId: artId });
|
const listIds = await runner.query(articleDeleteQueries.GET_LIST_IDS, { articleId: artId });
|
||||||
const { articlelistId, optionslistId } = listIds.rows[0] ?? {};
|
const { articlelistId, optionslistId } = listIds.rows[0] ?? {};
|
||||||
|
|
||||||
await tombstone({ companyId, entityType: 'article', entityId: artId }, runner);
|
await recordObit({ companyId, entityType: 'article', entityId: artId }, runner);
|
||||||
await runner.query(articleDeleteQueries.DELETE_PICS_BY_ARTICLE, { articleId: artId });
|
await runner.query(articleDeleteQueries.DELETE_PICS_BY_ARTICLE, { articleId: artId });
|
||||||
|
|
||||||
const deleted = await runner.query(articleDeleteQueries.DELETE_BY_ID, { articleId: artId });
|
const deleted = await runner.query(articleDeleteQueries.DELETE_BY_ID, { articleId: artId });
|
||||||
@@ -218,7 +218,7 @@ export default function del(provider) {
|
|||||||
const reversedIds = [...subtreeIds].reverse();
|
const reversedIds = [...subtreeIds].reverse();
|
||||||
for (const catId of reversedIds) {
|
for (const catId of reversedIds) {
|
||||||
await runner.query(sql, { id: catId });
|
await runner.query(sql, { id: catId });
|
||||||
await tombstone({ companyId, entityType: 'category', entityId: catId }, runner);
|
await recordObit({ companyId, entityType: 'category', entityId: catId }, runner);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import { DELETE_BY_COMPANY_AND_ID as MSSQL_DELETE_BY_COMPANY_AND_ID } from '../.
|
|||||||
import { DELETE_BY_COMPANY_AND_ID as SQLITE_DELETE_BY_COMPANY_AND_ID } from '../../providers/sqlite3/queries/customergroup.js';
|
import { DELETE_BY_COMPANY_AND_ID as SQLITE_DELETE_BY_COMPANY_AND_ID } from '../../providers/sqlite3/queries/customergroup.js';
|
||||||
import { isForeignKeyConstraintError } from '../../providers/provider.js';
|
import { isForeignKeyConstraintError } from '../../providers/provider.js';
|
||||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import recordTombstone from '../posterminal/recordTombstone.js';
|
import recordObituary from '../posterminal/recordObituary.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
export default function del(provider) {
|
export default function del(provider) {
|
||||||
const access = resolveSelectedCompanyAccess(provider);
|
const access = resolveSelectedCompanyAccess(provider);
|
||||||
const tombstone = recordTombstone(provider);
|
const recordObit = recordObituary(provider);
|
||||||
const sql =
|
const sql =
|
||||||
provider?.dialect === 'sqlite3'
|
provider?.dialect === 'sqlite3'
|
||||||
? SQLITE_DELETE_BY_COMPANY_AND_ID
|
? SQLITE_DELETE_BY_COMPANY_AND_ID
|
||||||
@@ -43,7 +43,7 @@ export default function del(provider) {
|
|||||||
throw new Error('Customer group not found');
|
throw new Error('Customer group not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await tombstone({ companyId, entityType: 'customergroup', entityId: id }, runner);
|
await recordObit({ companyId, entityType: 'customergroup', entityId: id }, runner);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (isForeignKeyConstraintError(err)) {
|
if (isForeignKeyConstraintError(err)) {
|
||||||
throw new Error('Customer group in use');
|
throw new Error('Customer group in use');
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import {
|
|||||||
GET_BY_COMPANY_AND_ID as SQLITE_GET_BY_ID,
|
GET_BY_COMPANY_AND_ID as SQLITE_GET_BY_ID,
|
||||||
} from '../../providers/sqlite3/queries/entity.js';
|
} from '../../providers/sqlite3/queries/entity.js';
|
||||||
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
import resolveSelectedCompanyAccess from '../companyuser/resolveSelectedCompanyAccess.js';
|
||||||
import recordTombstone from '../posterminal/recordTombstone.js';
|
import recordObituary from '../posterminal/recordObituary.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
export default function del(provider) {
|
export default function del(provider) {
|
||||||
const access = resolveSelectedCompanyAccess(provider);
|
const access = resolveSelectedCompanyAccess(provider);
|
||||||
const tombstone = recordTombstone(provider);
|
const recordObit = recordObituary(provider);
|
||||||
const isSqlite = provider?.dialect === 'sqlite3';
|
const isSqlite = provider?.dialect === 'sqlite3';
|
||||||
const sql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
|
const sql = isSqlite ? SQLITE_DELETE : MSSQL_DELETE;
|
||||||
const checkInUseSql = isSqlite ? SQLITE_CHECK_IN_USE : MSSQL_CHECK_IN_USE;
|
const checkInUseSql = isSqlite ? SQLITE_CHECK_IN_USE : MSSQL_CHECK_IN_USE;
|
||||||
@@ -66,7 +66,7 @@ export default function del(provider) {
|
|||||||
throw new Error('Entity not found');
|
throw new Error('Entity not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await tombstone({ companyId, entityType: 'customer', entityId: numericId }, runner);
|
await recordObit({ companyId, entityType: 'customer', entityId: numericId }, runner);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default function findByPairingpin(provider) {
|
|||||||
*
|
*
|
||||||
* @param {string} pairingpin - The pairing pin to search for.
|
* @param {string} pairingpin - The pairing pin to search for.
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
* @returns {Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknowntombstoneid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>} The posterminal, or null if not found.
|
* @returns {Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknownobituaryid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>} The posterminal, or null if not found.
|
||||||
*/
|
*/
|
||||||
return async (pairingpin, tx) => {
|
return async (pairingpin, tx) => {
|
||||||
if (!pairingpin) return null;
|
if (!pairingpin) return null;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default function findByToken(provider) {
|
|||||||
*
|
*
|
||||||
* @param {string} token - The auth token to search for.
|
* @param {string} token - The auth token to search for.
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
* @returns {Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknowntombstoneid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>} The posterminal, or null if not found.
|
* @returns {Promise<{id: number, companyId: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknownobituaryid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}|null>} The posterminal, or null if not found.
|
||||||
*/
|
*/
|
||||||
return async (token, tx) => {
|
return async (token, tx) => {
|
||||||
const trimmed = String(token ?? '').trim();
|
const trimmed = String(token ?? '').trim();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default function getDeletedEntityCount(provider) {
|
|||||||
*
|
*
|
||||||
* @param {object} input
|
* @param {object} input
|
||||||
* @param {number} input.posterminalId - The POS terminal id.
|
* @param {number} input.posterminalId - The POS terminal id.
|
||||||
* @param {number} [input.cursor=0] - The highest synced tombstone ID.
|
* @param {number} [input.cursor=0] - The highest synced obituary ID.
|
||||||
* @param {object} [tx] - Optional transaction.
|
* @param {object} [tx] - Optional transaction.
|
||||||
* @returns {Promise<number>} Count of deleted entities.
|
* @returns {Promise<number>} Count of deleted entities.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default function getDeletedEntityList(provider) {
|
|||||||
*
|
*
|
||||||
* @param {object} input
|
* @param {object} input
|
||||||
* @param {number} input.posterminalId - The POS terminal id.
|
* @param {number} input.posterminalId - The POS terminal id.
|
||||||
* @param {number} [input.cursor=0] - The highest synced tombstone ID.
|
* @param {number} [input.cursor=0] - The highest synced obituary ID.
|
||||||
* @param {number} [input.limit=200] - Max items to return.
|
* @param {number} [input.limit=200] - Max items to return.
|
||||||
* @param {object} [tx] - Optional transaction.
|
* @param {object} [tx] - Optional transaction.
|
||||||
* @returns {Promise<Array<{id: number, entityType: string, entityId: number}>>}
|
* @returns {Promise<Array<{id: number, entityType: string, entityId: number}>>}
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ export default function list(provider) {
|
|||||||
*
|
*
|
||||||
* @param {number} googleAuthId - The id of the Google auth user.
|
* @param {number} googleAuthId - The id of the Google auth user.
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
* @returns {Promise<Array<{id: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknowntombstoneid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}>>} The posterminals.
|
* @returns {Promise<Array<{id: number, name: string, token: string|null, pairingpin: string|null, pairedAt: string|null, clientserial: string|null, maxknownobituaryid: number|null, rootCategoryId: number|null, syncRootArticles: boolean|number, lastseenAt: string|null, updatedAt: string}>>} The posterminals.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const terminals = await store.posterminal.list(42);
|
* const terminals = await store.posterminal.list(42);
|
||||||
* // => [{ id, name, token, pairingpin, pairedAt, clientserial, maxknowntombstoneid, rootCategoryId, syncRootArticles, lastseenAt, updatedAt }]
|
* // => [{ id, name, token, pairingpin, pairedAt, clientserial, maxknownobituaryid, rootCategoryId, syncRootArticles, lastseenAt, updatedAt }]
|
||||||
*/
|
*/
|
||||||
return async (googleAuthId, tx) => {
|
return async (googleAuthId, tx) => {
|
||||||
const { companyId } = await access(googleAuthId, tx);
|
const { companyId } = await access(googleAuthId, tx);
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { RECORD_TOMBSTONE as MSSQL_SQL } from '../../providers/mssql/queries/posterminal.js';
|
import { RECORD_OBITUARY as MSSQL_SQL } from '../../providers/mssql/queries/posterminal.js';
|
||||||
import { RECORD_TOMBSTONE as SQLITE_SQL } from '../../providers/sqlite3/queries/posterminal.js';
|
import { RECORD_OBITUARY as SQLITE_SQL } from '../../providers/sqlite3/queries/posterminal.js';
|
||||||
import makeRunner from '../runner.js';
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
export default function recordTombstone(provider) {
|
export default function recordObituary(provider) {
|
||||||
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
|
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SQL : MSSQL_SQL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records a tombstone for all active paired POS terminals of a company.
|
* Records an obituary for all active paired POS terminals of a company.
|
||||||
*
|
*
|
||||||
* @param {object} input
|
* @param {object} input
|
||||||
* @param {number} input.companyId - The company id.
|
* @param {number} input.companyId - The company id.
|
||||||
27
src/store/posterminal/setMaxKnownObituaryId.js
Normal file
27
src/store/posterminal/setMaxKnownObituaryId.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { SET_MAX_KNOWN_OBITUARY_ID as MSSQL_SET } from '../../providers/mssql/queries/posterminal.js';
|
||||||
|
import { SET_MAX_KNOWN_OBITUARY_ID as SQLITE_SET } from '../../providers/sqlite3/queries/posterminal.js';
|
||||||
|
import makeRunner from '../runner.js';
|
||||||
|
|
||||||
|
export default function setMaxKnownObituaryId(provider) {
|
||||||
|
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SET : MSSQL_SET;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the max known obituary ID for a POS terminal.
|
||||||
|
*
|
||||||
|
* @param {number} id - The posterminal id.
|
||||||
|
* @param {number|null} maxknownobituaryid - The highest synced obituary ID.
|
||||||
|
* @param {object} [tx] - Optional transaction to run within.
|
||||||
|
* @returns {Promise<{id: number, maxknownobituaryid: number|null}>}
|
||||||
|
*/
|
||||||
|
return async (id, maxknownobituaryid, tx) => {
|
||||||
|
await makeRunner(provider, tx).query(sql, {
|
||||||
|
id,
|
||||||
|
maxknownobituaryid: maxknownobituaryid != null ? Number(maxknownobituaryid) : null,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
maxknownobituaryid: maxknownobituaryid != null ? Number(maxknownobituaryid) : null,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import { SET_MAX_KNOWN_TOMBSTONE_ID as MSSQL_SET } from '../../providers/mssql/queries/posterminal.js';
|
|
||||||
import { SET_MAX_KNOWN_TOMBSTONE_ID as SQLITE_SET } from '../../providers/sqlite3/queries/posterminal.js';
|
|
||||||
import makeRunner from '../runner.js';
|
|
||||||
|
|
||||||
export default function setMaxKnownTombstoneId(provider) {
|
|
||||||
const sql = provider?.dialect === 'sqlite3' ? SQLITE_SET : MSSQL_SET;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the max known tombstone ID for a POS terminal.
|
|
||||||
*
|
|
||||||
* @param {number} id - The posterminal id.
|
|
||||||
* @param {number|null} maxknowntombstoneid - The highest synced tombstone ID.
|
|
||||||
* @param {object} [tx] - Optional transaction to run within.
|
|
||||||
* @returns {Promise<{id: number, maxknowntombstoneid: number|null}>}
|
|
||||||
*/
|
|
||||||
return async (id, maxknowntombstoneid, tx) => {
|
|
||||||
await makeRunner(provider, tx).query(sql, {
|
|
||||||
id,
|
|
||||||
maxknowntombstoneid: maxknowntombstoneid != null ? Number(maxknowntombstoneid) : null,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
id,
|
|
||||||
maxknowntombstoneid: maxknowntombstoneid != null ? Number(maxknowntombstoneid) : null,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -21,13 +21,13 @@ export default function setOff(provider) {
|
|||||||
? SQLITE_LIST_CATEGORY_IDS
|
? SQLITE_LIST_CATEGORY_IDS
|
||||||
: MSSQL_LIST_CATEGORY_IDS;
|
: MSSQL_LIST_CATEGORY_IDS;
|
||||||
|
|
||||||
const addCategoryTombstoneSql = `
|
const addCategoryObituarySql = `
|
||||||
INSERT INTO posterminaltombstone (posterminal_id, entity_type, entity_id)
|
INSERT INTO posterminalobituary (posterminal_id, entity_type, entity_id)
|
||||||
VALUES (@posterminalId, 'category', @categoryId)
|
VALUES (@posterminalId, 'category', @categoryId)
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const addArticleTombstonesSql = `
|
const addArticleObituariesSql = `
|
||||||
INSERT INTO posterminaltombstone (posterminal_id, entity_type, entity_id)
|
INSERT INTO posterminalobituary (posterminal_id, entity_type, entity_id)
|
||||||
SELECT DISTINCT @posterminalId, 'article', ca.article_id
|
SELECT DISTINCT @posterminalId, 'article', ca.article_id
|
||||||
FROM categoryarticle ca
|
FROM categoryarticle ca
|
||||||
WHERE ca.category_id = @categoryId
|
WHERE ca.category_id = @categoryId
|
||||||
@@ -69,12 +69,12 @@ export default function setOff(provider) {
|
|||||||
throw new Error('Posterminal not found');
|
throw new Error('Posterminal not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await runner.query(addCategoryTombstoneSql, {
|
await runner.query(addCategoryObituarySql, {
|
||||||
posterminalId,
|
posterminalId,
|
||||||
categoryId,
|
categoryId,
|
||||||
});
|
});
|
||||||
|
|
||||||
await runner.query(addArticleTombstonesSql, {
|
await runner.query(addArticleObituariesSql, {
|
||||||
posterminalId,
|
posterminalId,
|
||||||
categoryId,
|
categoryId,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,15 +21,15 @@ export default function setOffAll(provider) {
|
|||||||
? SQLITE_LIST_CATEGORY_IDS
|
? SQLITE_LIST_CATEGORY_IDS
|
||||||
: MSSQL_LIST_CATEGORY_IDS;
|
: MSSQL_LIST_CATEGORY_IDS;
|
||||||
|
|
||||||
const addCategoryTombstonesSql = `
|
const addCategoryObituariesSql = `
|
||||||
INSERT INTO posterminaltombstone (posterminal_id, entity_type, entity_id)
|
INSERT INTO posterminalobituary (posterminal_id, entity_type, entity_id)
|
||||||
SELECT posterminal_id, 'category', category_id
|
SELECT posterminal_id, 'category', category_id
|
||||||
FROM posterminalcategory
|
FROM posterminalcategory
|
||||||
WHERE posterminal_id = @posterminalId
|
WHERE posterminal_id = @posterminalId
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const addArticleTombstonesSql = `
|
const addArticleObituariesSql = `
|
||||||
INSERT INTO posterminaltombstone (posterminal_id, entity_type, entity_id)
|
INSERT INTO posterminalobituary (posterminal_id, entity_type, entity_id)
|
||||||
SELECT DISTINCT pc.posterminal_id, 'article', ca.article_id
|
SELECT DISTINCT pc.posterminal_id, 'article', ca.article_id
|
||||||
FROM posterminalcategory pc
|
FROM posterminalcategory pc
|
||||||
INNER JOIN categoryarticle ca ON ca.category_id = pc.category_id
|
INNER JOIN categoryarticle ca ON ca.category_id = pc.category_id
|
||||||
@@ -64,8 +64,8 @@ export default function setOffAll(provider) {
|
|||||||
throw new Error('Posterminal not found');
|
throw new Error('Posterminal not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await runner.query(addCategoryTombstonesSql, { posterminalId });
|
await runner.query(addCategoryObituariesSql, { posterminalId });
|
||||||
await runner.query(addArticleTombstonesSql, { posterminalId });
|
await runner.query(addArticleObituariesSql, { posterminalId });
|
||||||
|
|
||||||
await runner.query(setOffAllSql, { posterminalId });
|
await runner.query(setOffAllSql, { posterminalId });
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ export default function setOn(provider) {
|
|||||||
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id = @categoryId
|
SELECT ca.article_id FROM categoryarticle ca WHERE ca.category_id = @categoryId
|
||||||
)`;
|
)`;
|
||||||
|
|
||||||
const clearTombstonesSql = `
|
const clearObituariesSql = `
|
||||||
DELETE FROM posterminaltombstone
|
DELETE FROM posterminalobituary
|
||||||
WHERE posterminal_id = @posterminalId
|
WHERE posterminal_id = @posterminalId
|
||||||
AND (
|
AND (
|
||||||
(entity_type = 'category' AND entity_id = @categoryId)
|
(entity_type = 'category' AND entity_id = @categoryId)
|
||||||
@@ -79,7 +79,7 @@ export default function setOn(provider) {
|
|||||||
categoryId,
|
categoryId,
|
||||||
});
|
});
|
||||||
|
|
||||||
await runner.query(clearTombstonesSql, {
|
await runner.query(clearObituariesSql, {
|
||||||
posterminalId,
|
posterminalId,
|
||||||
categoryId,
|
categoryId,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ export default function setOnAll(provider) {
|
|||||||
SET updated_at = SYSUTCDATETIME()
|
SET updated_at = SYSUTCDATETIME()
|
||||||
WHERE company_id = @companyId`;
|
WHERE company_id = @companyId`;
|
||||||
|
|
||||||
const clearTombstonesSql = `
|
const clearObituariesSql = `
|
||||||
DELETE FROM posterminaltombstone
|
DELETE FROM posterminalobituary
|
||||||
WHERE posterminal_id = @posterminalId
|
WHERE posterminal_id = @posterminalId
|
||||||
AND entity_type IN ('category', 'article')
|
AND entity_type IN ('category', 'article')
|
||||||
`;
|
`;
|
||||||
@@ -94,7 +94,7 @@ export default function setOnAll(provider) {
|
|||||||
rootCategoryId,
|
rootCategoryId,
|
||||||
});
|
});
|
||||||
|
|
||||||
await runner.query(clearTombstonesSql, {
|
await runner.query(clearObituariesSql, {
|
||||||
posterminalId,
|
posterminalId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -63,10 +63,10 @@ export default function upsert(provider) {
|
|||||||
? (input.pairingpin ? String(input.pairingpin).trim() : null)
|
? (input.pairingpin ? String(input.pairingpin).trim() : null)
|
||||||
: (existing.rows[0].pairingpin ?? null);
|
: (existing.rows[0].pairingpin ?? null);
|
||||||
|
|
||||||
const maxknowntombstoneid =
|
const maxknownobituaryid =
|
||||||
input.maxknowntombstoneid !== undefined
|
input.maxknownobituaryid !== undefined
|
||||||
? input.maxknowntombstoneid
|
? input.maxknownobituaryid
|
||||||
: (existing.rows[0].maxknowntombstoneid ?? null);
|
: (existing.rows[0].maxknownobituaryid ?? null);
|
||||||
|
|
||||||
const rootCategoryId =
|
const rootCategoryId =
|
||||||
input.rootCategoryId !== undefined
|
input.rootCategoryId !== undefined
|
||||||
@@ -91,7 +91,7 @@ export default function upsert(provider) {
|
|||||||
pairingpin,
|
pairingpin,
|
||||||
pairedAt,
|
pairedAt,
|
||||||
clientserial,
|
clientserial,
|
||||||
maxknowntombstoneid,
|
maxknownobituaryid,
|
||||||
rootCategoryId,
|
rootCategoryId,
|
||||||
syncRootArticles,
|
syncRootArticles,
|
||||||
lastseenAt,
|
lastseenAt,
|
||||||
@@ -104,7 +104,7 @@ export default function upsert(provider) {
|
|||||||
pairingpin,
|
pairingpin,
|
||||||
pairedAt,
|
pairedAt,
|
||||||
clientserial,
|
clientserial,
|
||||||
maxknowntombstoneid,
|
maxknownobituaryid,
|
||||||
rootCategoryId,
|
rootCategoryId,
|
||||||
syncRootArticles,
|
syncRootArticles,
|
||||||
lastseenAt,
|
lastseenAt,
|
||||||
@@ -112,7 +112,7 @@ export default function upsert(provider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pairingpin = input.pairingpin ? String(input.pairingpin).trim() : null;
|
const pairingpin = input.pairingpin ? String(input.pairingpin).trim() : null;
|
||||||
const maxknowntombstoneid = input.maxknowntombstoneid ?? null;
|
const maxknownobituaryid = input.maxknownobituaryid ?? null;
|
||||||
const rootCategoryId = input.rootCategoryId != null ? Number(input.rootCategoryId) : null;
|
const rootCategoryId = input.rootCategoryId != null ? Number(input.rootCategoryId) : null;
|
||||||
const syncRootArticles = input.syncRootArticles !== undefined ? (input.syncRootArticles ? 1 : 0) : 1;
|
const syncRootArticles = input.syncRootArticles !== undefined ? (input.syncRootArticles ? 1 : 0) : 1;
|
||||||
const lastseenAt = input.lastseenAt ?? null;
|
const lastseenAt = input.lastseenAt ?? null;
|
||||||
@@ -124,7 +124,7 @@ export default function upsert(provider) {
|
|||||||
pairingpin,
|
pairingpin,
|
||||||
pairedAt,
|
pairedAt,
|
||||||
clientserial,
|
clientserial,
|
||||||
maxknowntombstoneid,
|
maxknownobituaryid,
|
||||||
rootCategoryId,
|
rootCategoryId,
|
||||||
syncRootArticles,
|
syncRootArticles,
|
||||||
lastseenAt,
|
lastseenAt,
|
||||||
@@ -137,7 +137,7 @@ export default function upsert(provider) {
|
|||||||
pairingpin,
|
pairingpin,
|
||||||
pairedAt,
|
pairedAt,
|
||||||
clientserial,
|
clientserial,
|
||||||
maxknowntombstoneid,
|
maxknownobituaryid,
|
||||||
rootCategoryId,
|
rootCategoryId,
|
||||||
syncRootArticles,
|
syncRootArticles,
|
||||||
lastseenAt,
|
lastseenAt,
|
||||||
@@ -150,7 +150,7 @@ export default function upsert(provider) {
|
|||||||
pairingpin: row.pairingpin ?? null,
|
pairingpin: row.pairingpin ?? null,
|
||||||
pairedAt: row.pairedAt ?? null,
|
pairedAt: row.pairedAt ?? null,
|
||||||
clientserial: row.clientserial ?? null,
|
clientserial: row.clientserial ?? null,
|
||||||
maxknowntombstoneid: row.maxknowntombstoneid ?? null,
|
maxknownobituaryid: row.maxknownobituaryid ?? null,
|
||||||
rootCategoryId: row.rootCategoryId ?? null,
|
rootCategoryId: row.rootCategoryId ?? null,
|
||||||
syncRootArticles: row.syncRootArticles !== undefined ? (row.syncRootArticles ? 1 : 0) : 1,
|
syncRootArticles: row.syncRootArticles !== undefined ? (row.syncRootArticles ? 1 : 0) : 1,
|
||||||
lastseenAt: row.lastseenAt ?? null,
|
lastseenAt: row.lastseenAt ?? null,
|
||||||
|
|||||||
Reference in New Issue
Block a user