u
This commit is contained in:
@@ -548,7 +548,7 @@ Replaces the price list of an article by its SKU.
|
||||
| --- | --- | --- |
|
||||
| `googleAuthId` | `number` | The id of the Google auth user. |
|
||||
| `sku` | `string` | The article SKU. |
|
||||
| `prices` | `Array<{price: number, tax: number, minmultiplier?: number}>` | The price entries (minmultiplier defaults to 1). |
|
||||
| `prices` | `Array<{net?: number, gross?: number, price?: number, taxRate?: number, tax?: number, minmultiplier?: number}>` | The price entries (net or gross, taxRate or tax percentage, minmultiplier defaults to 1). |
|
||||
| `[tx]` | `object` | Optional transaction to run within. |
|
||||
|
||||
**Returns**
|
||||
@@ -562,7 +562,9 @@ Replaces the price list of an article by its SKU.
|
||||
**Example**
|
||||
|
||||
```js
|
||||
const article = await store.article.setPricesBySku(42, 'SKU-1', [{ price: 1.5, tax: 19, minmultiplier: 1 }]);
|
||||
const article = await store.article.setPricesBySku(42, 'SKU-1', [{ net: 10.0, taxRate: 19, minmultiplier: 1 }]);
|
||||
// or with gross:
|
||||
const article = await store.article.setPricesBySku(42, 'SKU-1', [{ gross: 11.9, taxRate: 19 }]);
|
||||
// => { id, sku, name, ... }
|
||||
```
|
||||
|
||||
|
||||
2
API.md
2
API.md
@@ -105,7 +105,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
|
||||
- `setCategoryIdsBySku(googleAuthId: number, sku: string, categoryIds: Array<number>, tx?: object): Promise<object>`
|
||||
- `setEansBySku(googleAuthId: number, sku: string, eans: Array<string>, tx?: object): Promise<object>`
|
||||
- `setParentBySku(googleAuthId: number, sku: string, parentSku: string|null, tx?: object): Promise<object>`
|
||||
- `setPricesBySku(googleAuthId: number, sku: string, prices: Array<{price: number, tax: number, minmultiplier?: number}>, tx?: object): Promise<object>`
|
||||
- `setPricesBySku(googleAuthId: number, sku: string, prices: Array<{net?: number, gross?: number, price?: number, taxRate?: number, tax?: number, minmultiplier?: number}>, tx?: object): Promise<object>`
|
||||
- `setTrackStockBySku(googleAuthId: number, sku: string, trackStock: boolean|number, tx?: object): Promise<object>`
|
||||
- `setWeightBySku(googleAuthId: number, sku: string, weight: number, tx?: object): Promise<object>`
|
||||
- `toggleParent(googleAuthId: number, sku: string, options: {isParent: boolean, attributeNameId?: number, parentAttributeNameId?: number}, tx?: object): Promise<object>`
|
||||
|
||||
@@ -42,8 +42,17 @@ export default function addImage(provider) {
|
||||
|
||||
const sortResult = await runner.query(getSortSql, { articleId });
|
||||
const sort = sortResult.rows[0].sort;
|
||||
const fullHash = newFullHash();
|
||||
const fullHash = newFullHash(processed.full.buffer);
|
||||
|
||||
let picId;
|
||||
const existingPic = await runner.query(
|
||||
'SELECT id FROM pic WHERE hash = @fullHash',
|
||||
{ fullHash },
|
||||
);
|
||||
|
||||
if (existingPic.rows[0]) {
|
||||
picId = existingPic.rows[0].id;
|
||||
} else {
|
||||
if (isSqlite) {
|
||||
if (runner.writePicFull) {
|
||||
await runner.writePicFull(fullHash, processed.full.buffer);
|
||||
@@ -67,17 +76,28 @@ export default function addImage(provider) {
|
||||
thumbbinary: processed.thumb.buffer,
|
||||
});
|
||||
|
||||
const picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||
picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||
}
|
||||
|
||||
const existingArticlePic = await runner.query(
|
||||
'SELECT id, sort FROM articlepic WHERE article_id = @articleId AND pic_id = @picId',
|
||||
{ articleId, picId },
|
||||
);
|
||||
|
||||
let effectiveSort = sort;
|
||||
if (existingArticlePic.rows[0]) {
|
||||
effectiveSort = existingArticlePic.rows[0].sort;
|
||||
} else {
|
||||
await runner.query(addArticlePicSql, {
|
||||
articleId,
|
||||
picId,
|
||||
sort,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
picId,
|
||||
sort,
|
||||
sort: effectiveSort,
|
||||
full: {
|
||||
w: processed.full.w,
|
||||
h: processed.full.h,
|
||||
|
||||
@@ -22,28 +22,37 @@ function normalizePrices(prices) {
|
||||
const normalized = [];
|
||||
|
||||
for (const entry of prices) {
|
||||
const price = entry?.price;
|
||||
const tax = entry?.tax;
|
||||
const rawTax = entry?.taxRate ?? entry?.tax;
|
||||
const minmultiplier =
|
||||
entry?.minmultiplier === undefined || entry?.minmultiplier === null
|
||||
? 1
|
||||
: entry.minmultiplier;
|
||||
|
||||
if (
|
||||
typeof price !== 'number' || !Number.isFinite(price) || price < 0 ||
|
||||
typeof tax !== 'number' || !Number.isFinite(tax) || tax < 0 ||
|
||||
typeof rawTax !== 'number' || !Number.isFinite(rawTax) || rawTax < 0 ||
|
||||
typeof minmultiplier !== 'number' || !Number.isFinite(minmultiplier) || minmultiplier <= 0
|
||||
) {
|
||||
throw new Error('Invalid prices');
|
||||
}
|
||||
|
||||
let netPrice;
|
||||
if (typeof entry?.net === 'number' && Number.isFinite(entry.net) && entry.net >= 0) {
|
||||
netPrice = entry.net;
|
||||
} else if (typeof entry?.price === 'number' && Number.isFinite(entry.price) && entry.price >= 0) {
|
||||
netPrice = entry.price;
|
||||
} else if (typeof entry?.gross === 'number' && Number.isFinite(entry.gross) && entry.gross >= 0) {
|
||||
netPrice = +Number(entry.gross / (1 + rawTax / 100)).toFixed(4);
|
||||
} else {
|
||||
throw new Error('Invalid prices');
|
||||
}
|
||||
|
||||
const key = String(minmultiplier);
|
||||
if (seen.has(key)) {
|
||||
throw new Error('Invalid prices');
|
||||
}
|
||||
seen.add(key);
|
||||
|
||||
normalized.push({ price, tax, minmultiplier });
|
||||
normalized.push({ price: netPrice, tax: rawTax, minmultiplier });
|
||||
}
|
||||
|
||||
return normalized;
|
||||
@@ -64,13 +73,15 @@ export default function setPricesBySku(provider) {
|
||||
*
|
||||
* @param {number} googleAuthId - The id of the Google auth user.
|
||||
* @param {string} sku - The article SKU.
|
||||
* @param {Array<{price: number, tax: number, minmultiplier?: number}>} prices - The price entries (minmultiplier defaults to 1).
|
||||
* @param {Array<{net?: number, gross?: number, price?: number, taxRate?: number, tax?: number, minmultiplier?: number}>} prices - The price entries (net or gross, taxRate or tax percentage, minmultiplier defaults to 1).
|
||||
* @param {object} [tx] - Optional transaction to run within.
|
||||
* @returns {Promise<object>} The updated article.
|
||||
* @throws {Error} If the prices are invalid or the article is not found.
|
||||
*
|
||||
* @example
|
||||
* const article = await store.article.setPricesBySku(42, 'SKU-1', [{ price: 1.5, tax: 19, minmultiplier: 1 }]);
|
||||
* const article = await store.article.setPricesBySku(42, 'SKU-1', [{ net: 10.0, taxRate: 19, minmultiplier: 1 }]);
|
||||
* // or with gross:
|
||||
* const article = await store.article.setPricesBySku(42, 'SKU-1', [{ gross: 11.9, taxRate: 19 }]);
|
||||
* // => { id, sku, name, ... }
|
||||
*/
|
||||
return async (googleAuthId, sku, prices, tx) => {
|
||||
|
||||
@@ -40,8 +40,17 @@ export default function addImage(provider) {
|
||||
await runner.query(deleteBrandPicSql, { brandId });
|
||||
|
||||
const sort = 0;
|
||||
const fullHash = newFullHash();
|
||||
const fullHash = newFullHash(processed.full.buffer);
|
||||
|
||||
let picId;
|
||||
const existingPic = await runner.query(
|
||||
'SELECT id FROM pic WHERE hash = @fullHash',
|
||||
{ fullHash },
|
||||
);
|
||||
|
||||
if (existingPic.rows[0]) {
|
||||
picId = existingPic.rows[0].id;
|
||||
} else {
|
||||
if (isSqlite) {
|
||||
if (runner.writePicFull) {
|
||||
await runner.writePicFull(fullHash, processed.full.buffer);
|
||||
@@ -65,7 +74,8 @@ export default function addImage(provider) {
|
||||
thumbbinary: processed.thumb.buffer,
|
||||
});
|
||||
|
||||
const picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||
picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||
}
|
||||
|
||||
const brandPicResult = await runner.query(addBrandPicSql, {
|
||||
brandId,
|
||||
|
||||
@@ -42,8 +42,17 @@ export default function addImage(provider) {
|
||||
|
||||
const sortResult = await runner.query(getSortSql, { categoryId });
|
||||
const sort = sortResult.rows[0].sort;
|
||||
const fullHash = newFullHash();
|
||||
const fullHash = newFullHash(processed.full.buffer);
|
||||
|
||||
let picId;
|
||||
const existingPic = await runner.query(
|
||||
'SELECT id FROM pic WHERE hash = @fullHash',
|
||||
{ fullHash },
|
||||
);
|
||||
|
||||
if (existingPic.rows[0]) {
|
||||
picId = existingPic.rows[0].id;
|
||||
} else {
|
||||
if (isSqlite) {
|
||||
if (runner.writePicFull) {
|
||||
await runner.writePicFull(fullHash, processed.full.buffer);
|
||||
@@ -67,13 +76,21 @@ export default function addImage(provider) {
|
||||
thumbbinary: processed.thumb.buffer,
|
||||
});
|
||||
|
||||
const picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||
picId = picResult.rows[0]?.id ?? picResult.insertId;
|
||||
}
|
||||
|
||||
const existingCategoryPic = await runner.query(
|
||||
'SELECT id, sort FROM categorypic WHERE category_id = @categoryId AND pic_id = @picId',
|
||||
{ categoryId, picId },
|
||||
);
|
||||
|
||||
if (!existingCategoryPic.rows[0]) {
|
||||
await runner.query(addCategoryPicSql, {
|
||||
categoryId,
|
||||
picId,
|
||||
sort,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
id: categoryId,
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { createHash, randomBytes } from 'node:crypto';
|
||||
|
||||
export default function newFullHash() {
|
||||
return randomBytes(32).toString('hex');
|
||||
const CHARSET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
export function toBase62(buffer) {
|
||||
let num = BigInt('0x' + buffer.toString('hex'));
|
||||
if (num === 0n) return CHARSET[0].repeat(8);
|
||||
let res = '';
|
||||
while (num > 0n) {
|
||||
res = CHARSET[Number(num % 62n)] + res;
|
||||
num /= 62n;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
export default function newFullHash(buffer) {
|
||||
if (buffer) {
|
||||
const digest = createHash('sha256').update(buffer).digest();
|
||||
return toBase62(digest).slice(0, 8);
|
||||
}
|
||||
const bytes = randomBytes(16);
|
||||
return toBase62(bytes).slice(0, 8);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user