This commit is contained in:
seb
2026-07-31 15:36:48 +02:00
parent 818d799f63
commit 6cc6dbb9e8
13 changed files with 1096 additions and 998 deletions

View File

@@ -122,6 +122,7 @@ Backend mapping:
| `createUnderParent` | `({ googleAuthId, parentId, name })` | `{ id, parentId, sort, name }` | | `createUnderParent` | `({ googleAuthId, parentId, name })` | `{ id, parentId, sort, name }` |
| `delete` | `({ googleAuthId, id })` | `void` — blocked by FK if `categoryarticle` or child categories remain | | `delete` | `({ googleAuthId, id })` | `void` — blocked by FK if `categoryarticle` or child categories remain |
| `getTreeForCompany` | `(googleAuthId, companyId)` | `{ languageId, tree, articles }` | | `getTreeForCompany` | `(googleAuthId, companyId)` | `{ languageId, tree, articles }` |
| `getCategoryArticles` | `(googleAuthId, categoryId)` | `{ id, sku, name, slug, net, taxRate, optionsCount, articleListCount, childCount, thumbW, thumbH, thumbHash }[]` |
### `createUnderParent` (transaction) ### `createUnderParent` (transaction)

View File

@@ -269,6 +269,7 @@ const CLUSTERS = [
'meta', 'meta',
'google_auth', 'google_auth',
'companyuser', 'companyuser',
'syncpos',
'company', 'company',
'customergroup', 'customergroup',
'entity', 'entity',

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 139 KiB

View File

@@ -98,6 +98,7 @@ const MENU = {
{ value: 'category.createUnderParent', label: 'createUnderParent', hint: 'googleAuthId, parentId, name → row' }, { value: 'category.createUnderParent', label: 'createUnderParent', hint: 'googleAuthId, parentId, name → row' },
{ 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, companyId → rows' },
{ value: 'category.getCategoryArticles', label: 'getCategoryArticles', hint: 'googleAuthId, categoryId → rows' },
], ],
}, },
companyuser: { companyuser: {
@@ -340,6 +341,19 @@ async function runMethod(client, action) {
await client.category.getTreeForCompany(Number(googleAuthId), Number(companyId)), await client.category.getTreeForCompany(Number(googleAuthId), Number(companyId)),
]; ];
} }
case 'category.getCategoryArticles': {
const googleAuthId = await askInt('google_auth id');
if (googleAuthId == null) return;
const categoryId = await askInt('category id');
if (categoryId == null) return;
return [
'rows',
await client.category.getCategoryArticles(
Number(googleAuthId),
Number(categoryId),
),
];
}
case 'companyuser.add': { case 'companyuser.add': {
const companyId = await askInt('Company id'); const companyId = await askInt('Company id');
if (companyId == null) return; if (companyId == null) return;

View File

@@ -6,6 +6,7 @@ import companyUpdate from './store/company/update.js';
import companyDelete from './store/company/delete.js'; import companyDelete from './store/company/delete.js';
import companyList from './store/company/list.js'; import companyList from './store/company/list.js';
import categoryGetTreeForCompany from './store/category/getTreeForCompany.js'; import categoryGetTreeForCompany from './store/category/getTreeForCompany.js';
import categoryGetCategoryArticles from './store/category/getCategoryArticles.js';
import categoryCreateUnderParent from './store/category/createUnderParent.js'; import categoryCreateUnderParent from './store/category/createUnderParent.js';
import categoryDelete from './store/category/delete.js'; import categoryDelete from './store/category/delete.js';
import langCreate from './store/lang/create.js'; import langCreate from './store/lang/create.js';
@@ -44,6 +45,7 @@ export default class LibDashStore {
this.category = { this.category = {
getTreeForCompany: categoryGetTreeForCompany(pool), getTreeForCompany: categoryGetTreeForCompany(pool),
getCategoryArticles: categoryGetCategoryArticles(pool),
createUnderParent: categoryCreateUnderParent(pool), createUnderParent: categoryCreateUnderParent(pool),
delete: categoryDelete(pool), delete: categoryDelete(pool),
}; };

View File

@@ -518,6 +518,21 @@ BEGIN
END END
`; `;
export const INIT_SYNCPOS = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'syncpos')
BEGIN
CREATE TABLE syncpos (
id INT IDENTITY(1,1) PRIMARY KEY,
company_id INT NOT NULL,
paircode NVARCHAR(50) NOT NULL,
token NVARCHAR(255) NULL,
CONSTRAINT FK_syncpos_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE,
CONSTRAINT UQ_syncpos_paircode UNIQUE (paircode),
CONSTRAINT UQ_syncpos_token UNIQUE (token)
);
END
`;
/** DDL scripts in dependency order for schema init. */ /** DDL scripts in dependency order for schema init. */
export const SCHEMA_SCRIPTS = [ export const SCHEMA_SCRIPTS = [
INIT_META, INIT_META,
@@ -552,4 +567,5 @@ export const SCHEMA_SCRIPTS = [
INIT_NUMBERS, INIT_NUMBERS,
INIT_GET_NEXT_NUMBER_WITH_PREFIX_AND_PADDING, INIT_GET_NEXT_NUMBER_WITH_PREFIX_AND_PADDING,
INIT_COMPANYUSER, INIT_COMPANYUSER,
INIT_SYNCPOS,
]; ];

View File

@@ -31,7 +31,7 @@ LEFT JOIN pic p ON p.id = first_pic.pic_id
ORDER BY t.sort, t.id ORDER BY t.sort, t.id
`; `;
export const GET_ROOT_CATEGORY_ARTICLES = ` export const GET_CATEGORY_ARTICLES = `
SELECT SELECT
a.id, a.id,
a.sku, a.sku,
@@ -79,7 +79,7 @@ OUTER APPLY (
ORDER BY ap.sort ASC, ap.id ASC ORDER BY ap.sort ASC, ap.id ASC
) first_pic ) first_pic
LEFT JOIN pic ON pic.id = first_pic.pic_id LEFT JOIN pic ON pic.id = first_pic.pic_id
WHERE ca.category_id = @rootCategoryId WHERE ca.category_id = @categoryId
ORDER BY a.id ORDER BY a.id
`; `;
@@ -111,6 +111,7 @@ SELECT
r.rootCategoryId, r.rootCategoryId,
co.id AS companyId, co.id AS companyId,
co.default_language_id AS languageId, co.default_language_id AS languageId,
co.poscustomergroup_id AS posCustomerGroupId,
cu.id AS companyuserId cu.id AS companyuserId
FROM category p FROM category p
LEFT JOIN root r ON 1 = 1 LEFT JOIN root r ON 1 = 1

View File

@@ -1,6 +1,7 @@
/** Drop order = reverse of schema create dependency order. */ /** Drop order = reverse of schema create dependency order. */
export const TABLES = [ export const TABLES = [
'companyuser', 'companyuser',
'syncpos',
'numbers', 'numbers',
'manifestarticle', 'manifestarticle',
'manifest', 'manifest',

View File

@@ -0,0 +1,16 @@
import resolveCategoryAccess from './resolveCategoryAccess.js';
import queryCategoryArticles from './queryCategoryArticles.js';
export default function getCategoryArticles(pool) {
const access = resolveCategoryAccess(pool);
const articles = queryCategoryArticles(pool);
return async (googleAuthId, categoryId) => {
const { languageId, posCustomerGroupId } = await access(
googleAuthId,
categoryId,
);
return articles({ categoryId, languageId, posCustomerGroupId });
};
}

View File

@@ -1,11 +1,10 @@
import { import { GET_TREE_FOR_COMPANY } from '../../sql/category.js';
GET_ROOT_CATEGORY_ARTICLES,
GET_TREE_FOR_COMPANY,
} from '../../sql/category.js';
import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js'; import resolveCompanyAccess from '../companyuser/resolveCompanyAccess.js';
import queryCategoryArticles from './queryCategoryArticles.js';
export default function getTreeForCompany(pool) { export default function getTreeForCompany(pool) {
const access = resolveCompanyAccess(pool); const access = resolveCompanyAccess(pool);
const articles = queryCategoryArticles(pool);
return async (googleAuthId, companyId) => { return async (googleAuthId, companyId) => {
const { rootCategoryId, languageId, posCustomerGroupId } = await access( const { rootCategoryId, languageId, posCustomerGroupId } = await access(
@@ -13,24 +12,19 @@ export default function getTreeForCompany(pool) {
companyId, companyId,
); );
const [treeResult, articlesResult] = await Promise.all([ const [treeResult, articleRows] = await Promise.all([
pool pool
.request() .request()
.input('rootId', rootCategoryId) .input('rootId', rootCategoryId)
.input('languageId', languageId) .input('languageId', languageId)
.query(GET_TREE_FOR_COMPANY), .query(GET_TREE_FOR_COMPANY),
pool articles({ categoryId: rootCategoryId, languageId, posCustomerGroupId }),
.request()
.input('rootCategoryId', rootCategoryId)
.input('languageId', languageId)
.input('posCustomerGroupId', posCustomerGroupId)
.query(GET_ROOT_CATEGORY_ARTICLES),
]); ]);
return { return {
languageId, languageId,
tree: treeResult.recordset, tree: treeResult.recordset,
articles: articlesResult.recordset, articles: articleRows,
}; };
}; };
} }

View File

@@ -0,0 +1,14 @@
import { GET_CATEGORY_ARTICLES } from '../../sql/category.js';
export default function queryCategoryArticles(pool) {
return async ({ categoryId, languageId, posCustomerGroupId }) => {
const result = await pool
.request()
.input('categoryId', categoryId)
.input('languageId', languageId)
.input('posCustomerGroupId', posCustomerGroupId)
.query(GET_CATEGORY_ARTICLES);
return result.recordset;
};
}

View File

@@ -23,6 +23,7 @@ export default function resolveCategoryAccess(pool) {
companyId: row.companyId, companyId: row.companyId,
rootCategoryId: row.rootCategoryId, rootCategoryId: row.rootCategoryId,
languageId: row.languageId, languageId: row.languageId,
posCustomerGroupId: row.posCustomerGroupId ?? null,
}; };
}; };
} }