@unchainedshop/plugins 2.5.12 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/events/node-event-emitter.js.map +1 -1
- package/lib/events/redis.js.map +1 -1
- package/lib/files/gridfs/gridfs-adapter.d.ts +1 -1
- package/lib/files/gridfs/gridfs-adapter.js +5 -1
- package/lib/files/gridfs/gridfs-adapter.js.map +1 -1
- package/lib/files/gridfs/index.d.ts +1 -1
- package/lib/files/gridfs/index.js +5 -12
- package/lib/files/gridfs/index.js.map +1 -1
- package/lib/files/minio/minio-adapter.d.ts +1 -1
- package/lib/files/minio/minio-adapter.js +9 -3
- package/lib/files/minio/minio-adapter.js.map +1 -1
- package/lib/filters/local-search.js +19 -1
- package/lib/filters/local-search.js.map +1 -1
- package/lib/payment/apple-iap/db/AppleTransactionsCollection.d.ts +4 -3
- package/lib/payment/apple-iap/db/AppleTransactionsCollection.js.map +1 -1
- package/lib/payment/apple-iap/module/configureAppleTransactionsModule.d.ts +2 -3
- package/lib/payment/apple-iap/module/configureAppleTransactionsModule.js +1 -1
- package/lib/payment/apple-iap/module/configureAppleTransactionsModule.js.map +1 -1
- package/lib/payment/cryptopay/db/CryptopayTransactions.d.ts +5 -5
- package/lib/payment/cryptopay/db/CryptopayTransactions.js.map +1 -1
- package/lib/payment/cryptopay/module/configureCryptopayModule.d.ts +1 -2
- package/lib/payment/cryptopay/module/configureCryptopayModule.js +3 -3
- package/lib/payment/cryptopay/module/configureCryptopayModule.js.map +1 -1
- package/lib/plugins-index.d.ts +4 -22
- package/lib/plugins-index.js.map +1 -1
- package/lib/pricing/delivery-swiss-tax.js +1 -1
- package/lib/pricing/discount-100-off.js +1 -1
- package/lib/pricing/discount-100-off.js.map +1 -1
- package/lib/pricing/discount-half-price-manual.js +1 -1
- package/lib/pricing/discount-half-price-manual.js.map +1 -1
- package/lib/pricing/discount-half-price.js +1 -1
- package/lib/pricing/discount-half-price.js.map +1 -1
- package/lib/pricing/order-discount.js +1 -1
- package/lib/pricing/order-items-discount.js +1 -1
- package/lib/pricing/order-payment.js +1 -1
- package/lib/pricing/order-round.d.ts +10 -0
- package/lib/pricing/order-round.js +113 -0
- package/lib/pricing/order-round.js.map +1 -0
- package/lib/pricing/product-discount.js +1 -1
- package/lib/pricing/product-price-rateconversion.js +1 -1
- package/lib/pricing/product-price-rateconversion.js.map +1 -1
- package/lib/pricing/product-round.d.ts +10 -0
- package/lib/pricing/product-round.js +45 -0
- package/lib/pricing/product-round.js.map +1 -0
- package/lib/pricing/product-swiss-tax.js +1 -1
- package/lib/pricing/product-swiss-tax.js.map +1 -1
- package/lib/warehousing/eth-minter.js +2 -1
- package/lib/warehousing/eth-minter.js.map +1 -1
- package/lib/warehousing/google-sheets.js +2 -2
- package/lib/warehousing/google-sheets.js.map +1 -1
- package/lib/worker/bulk-import.js +7 -9
- package/lib/worker/bulk-import.js.map +1 -1
- package/lib/worker/export-token.js +2 -1
- package/lib/worker/export-token.js.map +1 -1
- package/lib/worker/update-coinbase-rates.js +0 -1
- package/lib/worker/update-coinbase-rates.js.map +1 -1
- package/lib/worker/update-ecb-rates.js.map +1 -1
- package/lib/worker/update-token-ownership.js +2 -1
- package/lib/worker/update-token-ownership.js.map +1 -1
- package/package.json +30 -28
- package/src/events/node-event-emitter.ts +1 -2
- package/src/events/redis.ts +1 -2
- package/src/files/gridfs/gridfs-adapter.ts +8 -2
- package/src/files/gridfs/index.ts +5 -13
- package/src/files/minio/minio-adapter.ts +12 -4
- package/src/filters/local-search.ts +27 -4
- package/src/payment/apple-iap/db/AppleTransactionsCollection.ts +4 -3
- package/src/payment/apple-iap/module/configureAppleTransactionsModule.ts +1 -6
- package/src/payment/cryptopay/db/CryptopayTransactions.ts +5 -5
- package/src/payment/cryptopay/module/configureCryptopayModule.ts +4 -5
- package/src/plugins-index.ts +7 -2
- package/src/pricing/delivery-swiss-tax.ts +1 -1
- package/src/pricing/discount-100-off.ts +1 -1
- package/src/pricing/discount-half-price-manual.ts +1 -1
- package/src/pricing/discount-half-price.ts +1 -1
- package/src/pricing/order-discount.ts +1 -1
- package/src/pricing/order-items-discount.ts +1 -1
- package/src/pricing/order-payment.ts +1 -1
- package/src/pricing/order-round.ts +139 -0
- package/src/pricing/product-discount.ts +1 -1
- package/src/pricing/product-price-rateconversion.ts +1 -1
- package/src/pricing/product-round.ts +63 -0
- package/src/pricing/product-swiss-tax.test.ts +4 -4
- package/src/pricing/product-swiss-tax.ts +3 -3
- package/src/warehousing/eth-minter.ts +2 -1
- package/src/warehousing/google-sheets.ts +2 -2
- package/src/worker/bulk-import.ts +14 -20
- package/src/worker/export-token.ts +3 -2
- package/src/worker/update-coinbase-rates.ts +0 -1
- package/src/worker/update-ecb-rates.ts +4 -5
- package/src/worker/update-token-ownership.ts +2 -1
- package/lib/pricing/product-price-round.d.ts +0 -12
- package/lib/pricing/product-price-round.js +0 -53
- package/lib/pricing/product-price-round.js.map +0 -1
- package/src/pricing/configureProductPriceRounding.test.ts +0 -42
- package/src/pricing/product-price-round.ts +0 -75
|
@@ -1,30 +1,22 @@
|
|
|
1
|
-
import mongodb from 'mongodb';
|
|
1
|
+
import { mongodb } from '@unchainedshop/mongodb';
|
|
2
2
|
|
|
3
3
|
export const configureGridFSFileUploadModule = ({ db }) => {
|
|
4
|
-
// eslint-disable-next-line
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
const isMeteor = typeof Meteor === 'object';
|
|
7
|
-
|
|
8
4
|
// eslint-disable-next-line
|
|
9
5
|
let { GridFSBucket } = mongodb;
|
|
10
|
-
if (isMeteor) {
|
|
11
|
-
const { MongoInternals } = require('meteor/mongo'); // eslint-disable-line
|
|
12
|
-
GridFSBucket = MongoInternals.NpmModule.GridFSBucket;
|
|
13
|
-
}
|
|
14
6
|
|
|
15
7
|
return {
|
|
16
8
|
createWriteStream: async (directoryName, fileId, fileName) => {
|
|
17
|
-
const options = { bucketName: `file_uploads_${directoryName}
|
|
9
|
+
const options = { bucketName: `file_uploads_${directoryName}` };
|
|
18
10
|
const bucket = new GridFSBucket(db, options);
|
|
19
|
-
return bucket.openUploadStreamWithId(fileId, fileName
|
|
11
|
+
return bucket.openUploadStreamWithId(fileId, fileName);
|
|
20
12
|
},
|
|
21
13
|
createReadStream: async (directoryName, fileId) => {
|
|
22
|
-
const options = { bucketName: `file_uploads_${directoryName}
|
|
14
|
+
const options = { bucketName: `file_uploads_${directoryName}` };
|
|
23
15
|
const bucket = new GridFSBucket(db, options);
|
|
24
16
|
return bucket.openDownloadStream(fileId);
|
|
25
17
|
},
|
|
26
18
|
removeFileFromBucket: async (directoryName, fileId) => {
|
|
27
|
-
const options = { bucketName: `file_uploads_${directoryName}
|
|
19
|
+
const options = { bucketName: `file_uploads_${directoryName}` };
|
|
28
20
|
const bucket = new GridFSBucket(db, options);
|
|
29
21
|
return bucket.delete(fileId);
|
|
30
22
|
},
|
|
@@ -2,12 +2,13 @@ import https from 'https';
|
|
|
2
2
|
import http, { OutgoingHttpHeaders } from 'http';
|
|
3
3
|
import { Readable } from 'stream';
|
|
4
4
|
import { URL } from 'url';
|
|
5
|
-
import {
|
|
5
|
+
import { UploadFileData } from '@unchainedshop/types/files.js';
|
|
6
6
|
import {
|
|
7
7
|
FileAdapter,
|
|
8
8
|
FileDirector,
|
|
9
9
|
buildHashedFilename,
|
|
10
10
|
resolveExpirationDate,
|
|
11
|
+
IFileAdapter,
|
|
11
12
|
} from '@unchainedshop/file-upload';
|
|
12
13
|
|
|
13
14
|
import { log, LogLevel } from '@unchainedshop/logger';
|
|
@@ -90,7 +91,7 @@ connectToMinio().then(function setClient(c) {
|
|
|
90
91
|
client = c;
|
|
91
92
|
});
|
|
92
93
|
|
|
93
|
-
const
|
|
94
|
+
const createHttpDownloadStream = async (
|
|
94
95
|
fileUrl: string,
|
|
95
96
|
headers: OutgoingHttpHeaders,
|
|
96
97
|
): Promise<http.IncomingMessage> => {
|
|
@@ -211,8 +212,8 @@ export const MinioAdapter: IFileAdapter = {
|
|
|
211
212
|
const fileName = fname || href.split('/').pop();
|
|
212
213
|
const _id = buildHashedFilename(directoryName, fileName, new Date());
|
|
213
214
|
|
|
214
|
-
const stream = await
|
|
215
|
-
const type = stream
|
|
215
|
+
const stream = await createHttpDownloadStream(fileLink, headers);
|
|
216
|
+
const type = mimeType.lookup(fileName) || stream.headers['content-type'];
|
|
216
217
|
|
|
217
218
|
const metaData = {
|
|
218
219
|
'Content-Type': type,
|
|
@@ -237,6 +238,13 @@ export const MinioAdapter: IFileAdapter = {
|
|
|
237
238
|
url: generateMinioUrl(directoryName, _id),
|
|
238
239
|
} as UploadFileData;
|
|
239
240
|
},
|
|
241
|
+
|
|
242
|
+
async createDownloadStream(file) {
|
|
243
|
+
if (!client) throw new Error('Minio not connected, check env variables');
|
|
244
|
+
|
|
245
|
+
const stream = await client.getObject(MINIO_BUCKET_NAME, generateMinioPath(file.path, file._id));
|
|
246
|
+
return stream;
|
|
247
|
+
},
|
|
240
248
|
};
|
|
241
249
|
|
|
242
250
|
FileDirector.registerAdapter(MinioAdapter);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { FilterDirector, FilterAdapter } from '@unchainedshop/core-filters';
|
|
2
2
|
import { IFilterAdapter } from '@unchainedshop/types/filters.js';
|
|
3
|
-
import { Query } from '@unchainedshop/types/common.js';
|
|
4
3
|
import escapeStringRegexp from 'escape-string-regexp';
|
|
4
|
+
import { mongodb } from '@unchainedshop/mongodb';
|
|
5
|
+
import { ProductText } from '@unchainedshop/types/products.js';
|
|
6
|
+
import { AssortmentText } from '@unchainedshop/types/assortments.js';
|
|
5
7
|
|
|
6
8
|
const { AMAZON_DOCUMENTDB_COMPAT_MODE } = process.env;
|
|
7
9
|
|
|
@@ -11,7 +13,7 @@ const LocalSearch: IFilterAdapter = {
|
|
|
11
13
|
key: 'shop.unchained.filters.local-search',
|
|
12
14
|
label: 'Simple Fulltext search with MongoDB',
|
|
13
15
|
version: '1.0.0',
|
|
14
|
-
orderIndex:
|
|
16
|
+
orderIndex: 10,
|
|
15
17
|
|
|
16
18
|
actions: (params) => {
|
|
17
19
|
return {
|
|
@@ -23,7 +25,7 @@ const LocalSearch: IFilterAdapter = {
|
|
|
23
25
|
|
|
24
26
|
if (!queryString) return productIds;
|
|
25
27
|
|
|
26
|
-
const selector:
|
|
28
|
+
const selector: mongodb.Filter<ProductText> = AMAZON_DOCUMENTDB_COMPAT_MODE
|
|
27
29
|
? {
|
|
28
30
|
$or: [
|
|
29
31
|
{ title: { $regex: `${escapeStringRegexp(queryString)}`, $options: 'im' } },
|
|
@@ -59,7 +61,7 @@ const LocalSearch: IFilterAdapter = {
|
|
|
59
61
|
return assortmentIds;
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
const selector:
|
|
64
|
+
const selector: mongodb.Filter<AssortmentText> = {
|
|
63
65
|
$text: { $search: queryString },
|
|
64
66
|
};
|
|
65
67
|
|
|
@@ -75,6 +77,27 @@ const LocalSearch: IFilterAdapter = {
|
|
|
75
77
|
|
|
76
78
|
return assortments.map(({ assortmentId }) => assortmentId);
|
|
77
79
|
},
|
|
80
|
+
|
|
81
|
+
async transformFilterSelector(last) {
|
|
82
|
+
const { queryString, filterIds, includeInactive } = params.searchQuery;
|
|
83
|
+
|
|
84
|
+
if (queryString && !filterIds) {
|
|
85
|
+
// Global search without assortment scope:
|
|
86
|
+
// Return all filters
|
|
87
|
+
const selector = { ...last };
|
|
88
|
+
if (selector?.key) {
|
|
89
|
+
// Do not restrict to keys
|
|
90
|
+
delete selector.key;
|
|
91
|
+
}
|
|
92
|
+
if (!includeInactive) {
|
|
93
|
+
// Include only active filters
|
|
94
|
+
selector.isActive = true;
|
|
95
|
+
}
|
|
96
|
+
return selector;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return last;
|
|
100
|
+
},
|
|
78
101
|
};
|
|
79
102
|
},
|
|
80
103
|
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mongodb } from '@unchainedshop/mongodb';
|
|
2
|
+
import { TimestampFields } from '@unchainedshop/types/common.js';
|
|
2
3
|
|
|
3
4
|
export type AppleTransaction = {
|
|
4
|
-
_id?:
|
|
5
|
+
_id?: string;
|
|
5
6
|
matchedTransaction: any;
|
|
6
7
|
orderId: string;
|
|
7
8
|
} & TimestampFields;
|
|
8
9
|
|
|
9
|
-
export const AppleTransactionsCollection = async (db: Db) => {
|
|
10
|
+
export const AppleTransactionsCollection = async (db: mongodb.Db) => {
|
|
10
11
|
const AppleTransactions = db.collection<AppleTransaction>('payment_apple_iap_processed_transactions');
|
|
11
12
|
|
|
12
13
|
return AppleTransactions;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Db } from '@unchainedshop/types/common.js';
|
|
2
1
|
import { AppleTransaction, AppleTransactionsCollection } from '../db/AppleTransactionsCollection.js';
|
|
3
2
|
|
|
4
3
|
export interface AppleTransactionsModule {
|
|
@@ -7,11 +6,7 @@ export interface AppleTransactionsModule {
|
|
|
7
6
|
createTransaction: (doc: AppleTransaction, userId: string) => Promise<string | null>;
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
export const configureAppleTransactionsModule = async ({
|
|
11
|
-
db,
|
|
12
|
-
}: {
|
|
13
|
-
db: Db;
|
|
14
|
-
}): Promise<AppleTransactionsModule> => {
|
|
9
|
+
export const configureAppleTransactionsModule = async ({ db }): Promise<AppleTransactionsModule> => {
|
|
15
10
|
const AppleTransactions = await AppleTransactionsCollection(db);
|
|
16
11
|
|
|
17
12
|
return {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { TimestampFields } from '@unchainedshop/types/common.js';
|
|
2
|
+
import { mongodb } from '@unchainedshop/mongodb';
|
|
3
3
|
|
|
4
4
|
export type CryptopayTransaction = {
|
|
5
|
-
_id?:
|
|
5
|
+
_id?: string;
|
|
6
6
|
blockHeight: number;
|
|
7
7
|
mostRecentBlockHeight: number;
|
|
8
|
-
amount: Decimal128;
|
|
8
|
+
amount: mongodb.Decimal128;
|
|
9
9
|
currency: string;
|
|
10
10
|
decimals: number;
|
|
11
11
|
contract: string;
|
|
12
12
|
orderPaymentId?: string;
|
|
13
13
|
} & TimestampFields;
|
|
14
14
|
|
|
15
|
-
export const CryptopayTransactionsCollection = (db: Db) => {
|
|
15
|
+
export const CryptopayTransactionsCollection = (db: mongodb.Db) => {
|
|
16
16
|
return db.collection<CryptopayTransaction>('cryptopay_transactions');
|
|
17
17
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Decimal128 } from 'mongodb';
|
|
1
|
+
import { mongodb } from '@unchainedshop/mongodb';
|
|
3
2
|
import { CryptopayTransaction, CryptopayTransactionsCollection } from '../db/CryptopayTransactions.js';
|
|
4
3
|
|
|
5
4
|
export interface CryptopayModule {
|
|
@@ -23,7 +22,7 @@ export interface CryptopayModule {
|
|
|
23
22
|
getNextDerivationNumber: (currency: string) => Promise<number>;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
export const configureCryptopayModule = ({ db }
|
|
25
|
+
export const configureCryptopayModule = ({ db }): CryptopayModule => {
|
|
27
26
|
const CryptoTransactions = CryptopayTransactionsCollection(db);
|
|
28
27
|
|
|
29
28
|
const getWalletAddress: CryptopayModule['getWalletAddress'] = async (addressId) => {
|
|
@@ -64,7 +63,7 @@ export const configureCryptopayModule = ({ db }: { db: Db }): CryptopayModule =>
|
|
|
64
63
|
decimals: null,
|
|
65
64
|
mostRecentBlockHeight: 0,
|
|
66
65
|
blockHeight: 0,
|
|
67
|
-
amount: Decimal128.fromString('0'),
|
|
66
|
+
amount: mongodb.Decimal128.fromString('0'),
|
|
68
67
|
created: new Date(),
|
|
69
68
|
},
|
|
70
69
|
$set: {
|
|
@@ -112,7 +111,7 @@ export const configureCryptopayModule = ({ db }: { db: Db }): CryptopayModule =>
|
|
|
112
111
|
decimals,
|
|
113
112
|
blockHeight,
|
|
114
113
|
mostRecentBlockHeight: blockHeight,
|
|
115
|
-
amount: Decimal128.fromString(amount),
|
|
114
|
+
amount: mongodb.Decimal128.fromString(amount),
|
|
116
115
|
updated: new Date(),
|
|
117
116
|
},
|
|
118
117
|
},
|
package/src/plugins-index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useMiddlewareWithCurrentContext } from '@unchainedshop/api/express/index.js';
|
|
2
|
-
import { UnchainedCore } from '@unchainedshop/types/core.js';
|
|
2
|
+
import { ModuleInput, UnchainedCore } from '@unchainedshop/types/core.js';
|
|
3
3
|
import express from 'express';
|
|
4
4
|
|
|
5
5
|
// Delivery
|
|
@@ -89,7 +89,12 @@ const {
|
|
|
89
89
|
// import './files/minio/minio-adapter';
|
|
90
90
|
// import { minioHandler } from './files/minio/minio-webhook';
|
|
91
91
|
|
|
92
|
-
export const defaultModules
|
|
92
|
+
export const defaultModules: Record<
|
|
93
|
+
string,
|
|
94
|
+
{
|
|
95
|
+
configure: (params: ModuleInput<any>) => any;
|
|
96
|
+
}
|
|
97
|
+
> = {
|
|
93
98
|
appleTransactions: {
|
|
94
99
|
configure: configureAppleTransactionsModule,
|
|
95
100
|
},
|
|
@@ -33,7 +33,7 @@ export const DeliverySwissTax: IDeliveryPricingAdapter = {
|
|
|
33
33
|
key: 'shop.unchained.pricing.delivery-swiss-tax',
|
|
34
34
|
version: '1.0.0',
|
|
35
35
|
label: 'Apply Swiss Tax on Delivery Fees',
|
|
36
|
-
orderIndex:
|
|
36
|
+
orderIndex: 80,
|
|
37
37
|
|
|
38
38
|
isActivatedFor: (context) => {
|
|
39
39
|
return isDeliveryAddressInSwitzerland(context);
|
|
@@ -7,7 +7,7 @@ export const HundredOff: IDiscountAdapter = {
|
|
|
7
7
|
key: 'shop.unchained.discount.100-off',
|
|
8
8
|
label: '100 Off',
|
|
9
9
|
version: '1.0.0',
|
|
10
|
-
orderIndex:
|
|
10
|
+
orderIndex: 10,
|
|
11
11
|
|
|
12
12
|
// return true if a discount is allowed to get added manually by a user
|
|
13
13
|
isManualAdditionAllowed: async () => {
|
|
@@ -7,7 +7,7 @@ export const HalfPriceManual: IDiscountAdapter = {
|
|
|
7
7
|
key: 'shop.unchained.discount.half-price-manual',
|
|
8
8
|
label: 'Half Price Manual',
|
|
9
9
|
version: '1.0.0',
|
|
10
|
-
orderIndex:
|
|
10
|
+
orderIndex: 10,
|
|
11
11
|
|
|
12
12
|
// return true if a discount is allowed to get added manually by a user
|
|
13
13
|
isManualAdditionAllowed: async () => {
|
|
@@ -7,7 +7,7 @@ export const HalfPrice: IDiscountAdapter = {
|
|
|
7
7
|
key: 'shop.unchained.discount.half-price',
|
|
8
8
|
label: 'Half Price',
|
|
9
9
|
version: '1.0.0',
|
|
10
|
-
orderIndex:
|
|
10
|
+
orderIndex: 10,
|
|
11
11
|
|
|
12
12
|
// return true if a discount is allowed to get added manually by a user
|
|
13
13
|
isManualAdditionAllowed: async () => {
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { OrderPricingAdapter, OrderPricingDirector } from '@unchainedshop/core-orders';
|
|
2
|
+
import { IOrderPricingAdapter, OrderPricingRowCategory } from '@unchainedshop/types/orders.pricing.js';
|
|
3
|
+
|
|
4
|
+
interface PriceRoundSettings {
|
|
5
|
+
defaultPrecision: number;
|
|
6
|
+
roundTo: (value: number, precision: number, currency: string) => number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const OrderPriceRound: IOrderPricingAdapter & {
|
|
10
|
+
configure: (params: PriceRoundSettings) => void;
|
|
11
|
+
settings: PriceRoundSettings;
|
|
12
|
+
} = {
|
|
13
|
+
...OrderPricingAdapter,
|
|
14
|
+
|
|
15
|
+
key: 'shop.unchained.pricing.order-round',
|
|
16
|
+
version: '1.0.0',
|
|
17
|
+
label: 'Round order price to the next precision number',
|
|
18
|
+
orderIndex: 90,
|
|
19
|
+
|
|
20
|
+
isActivatedFor: () => {
|
|
21
|
+
return true;
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
settings: {
|
|
25
|
+
defaultPrecision: 5,
|
|
26
|
+
roundTo: (value: number, precision: number) =>
|
|
27
|
+
precision !== 0 ? Math.round(value / precision) * precision : value,
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
configure({ defaultPrecision, roundTo }) {
|
|
31
|
+
if (defaultPrecision) this.settings.defaultPrecision = defaultPrecision;
|
|
32
|
+
if (roundTo) this.settings.roundTo = roundTo;
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
actions: (params) => {
|
|
36
|
+
const pricingAdapter = OrderPricingAdapter.actions(params);
|
|
37
|
+
|
|
38
|
+
const calculateDifference = (amount: number, currency: string) => {
|
|
39
|
+
const roundedAmount = OrderPriceRound.settings.roundTo(
|
|
40
|
+
amount,
|
|
41
|
+
OrderPriceRound.settings.defaultPrecision,
|
|
42
|
+
currency,
|
|
43
|
+
);
|
|
44
|
+
return roundedAmount - amount;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
...pricingAdapter,
|
|
49
|
+
|
|
50
|
+
calculate: async () => {
|
|
51
|
+
const { currency } = params.context;
|
|
52
|
+
|
|
53
|
+
const { amount: deliveryAmount } = params.calculationSheet.total({
|
|
54
|
+
category: OrderPricingRowCategory.Delivery,
|
|
55
|
+
useNetPrice: true,
|
|
56
|
+
});
|
|
57
|
+
if (deliveryAmount) {
|
|
58
|
+
pricingAdapter.resultSheet().addDelivery({
|
|
59
|
+
amount: calculateDifference(deliveryAmount, currency),
|
|
60
|
+
taxAmount: 0,
|
|
61
|
+
meta: {
|
|
62
|
+
adapter: OrderPriceRound.key,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const { amount: discountAmount } = params.calculationSheet.total({
|
|
68
|
+
category: OrderPricingRowCategory.Discounts,
|
|
69
|
+
useNetPrice: true,
|
|
70
|
+
});
|
|
71
|
+
if (discountAmount) {
|
|
72
|
+
pricingAdapter.resultSheet().addDiscount({
|
|
73
|
+
amount: calculateDifference(discountAmount, currency),
|
|
74
|
+
taxAmount: 0,
|
|
75
|
+
meta: {
|
|
76
|
+
adapter: OrderPriceRound.key,
|
|
77
|
+
},
|
|
78
|
+
discountId: null,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const { amount: itemsAmount } = params.calculationSheet.total({
|
|
83
|
+
category: OrderPricingRowCategory.Items,
|
|
84
|
+
useNetPrice: true,
|
|
85
|
+
});
|
|
86
|
+
if (itemsAmount) {
|
|
87
|
+
pricingAdapter.resultSheet().addItems({
|
|
88
|
+
amount: calculateDifference(itemsAmount, currency),
|
|
89
|
+
taxAmount: 0,
|
|
90
|
+
meta: {
|
|
91
|
+
adapter: OrderPriceRound.key,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const { amount: paymentAmount } = params.calculationSheet.total({
|
|
97
|
+
category: OrderPricingRowCategory.Payment,
|
|
98
|
+
useNetPrice: true,
|
|
99
|
+
});
|
|
100
|
+
if (paymentAmount) {
|
|
101
|
+
pricingAdapter.resultSheet().addPayment({
|
|
102
|
+
amount: calculateDifference(paymentAmount, currency),
|
|
103
|
+
taxAmount: 0,
|
|
104
|
+
meta: {
|
|
105
|
+
adapter: OrderPriceRound.key,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const taxesAmount = params.calculationSheet.taxSum({
|
|
111
|
+
category: OrderPricingRowCategory.Taxes,
|
|
112
|
+
});
|
|
113
|
+
if (taxesAmount) {
|
|
114
|
+
const taxDifference = calculateDifference(taxesAmount, currency);
|
|
115
|
+
pricingAdapter.resultSheet().calculation.push({
|
|
116
|
+
category: OrderPricingRowCategory.Taxes,
|
|
117
|
+
amount: taxDifference,
|
|
118
|
+
meta: {
|
|
119
|
+
adapter: OrderPriceRound.key,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
// WORKAROUND BECAUSE ORDER TOTAL GROSS PRICE IS CALCULATED WITH A SUM OF EVERYTHING EXCEPT TAXES
|
|
123
|
+
// AS OF UNCHAINED <= 2.6
|
|
124
|
+
pricingAdapter.resultSheet().calculation.push({
|
|
125
|
+
category: null,
|
|
126
|
+
amount: taxDifference,
|
|
127
|
+
meta: {
|
|
128
|
+
adapter: OrderPriceRound.key,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return pricingAdapter.calculate();
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
OrderPricingDirector.registerAdapter(OrderPriceRound);
|
|
@@ -7,7 +7,7 @@ export const ProductPriceRateConversion: IProductPricingAdapter = {
|
|
|
7
7
|
key: 'shop.unchained.pricing.rate-conversion',
|
|
8
8
|
version: '1.0.0',
|
|
9
9
|
label: 'Generic rate conversion plugin that converts between rates if entry in DB exists.',
|
|
10
|
-
orderIndex:
|
|
10
|
+
orderIndex: 10,
|
|
11
11
|
|
|
12
12
|
isActivatedFor: () => {
|
|
13
13
|
return true;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing.js';
|
|
2
|
+
import { ProductPricingAdapter, ProductPricingDirector } from '@unchainedshop/core-products';
|
|
3
|
+
|
|
4
|
+
interface PriceRoundSettings {
|
|
5
|
+
defaultPrecision: number;
|
|
6
|
+
roundTo: (value: number, precision: number, currency: string) => number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const ProductRound: IProductPricingAdapter & {
|
|
10
|
+
configure: (params: PriceRoundSettings) => void;
|
|
11
|
+
settings: PriceRoundSettings;
|
|
12
|
+
} = {
|
|
13
|
+
...ProductPricingAdapter,
|
|
14
|
+
|
|
15
|
+
key: 'shop.unchained.pricing.product-round',
|
|
16
|
+
version: '1.0.0',
|
|
17
|
+
label: 'Round product price',
|
|
18
|
+
orderIndex: 90,
|
|
19
|
+
|
|
20
|
+
isActivatedFor: () => {
|
|
21
|
+
return true;
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
settings: {
|
|
25
|
+
defaultPrecision: 5,
|
|
26
|
+
roundTo: (value: number, precision: number) => Math.round(value / precision) * precision,
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
configure({ defaultPrecision, roundTo }) {
|
|
30
|
+
if (defaultPrecision) this.settings.defaultPrecision = defaultPrecision;
|
|
31
|
+
if (roundTo) this.settings.roundTo = roundTo;
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
actions: (params) => {
|
|
35
|
+
const pricingAdapter = ProductPricingAdapter.actions(params);
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
...pricingAdapter,
|
|
39
|
+
|
|
40
|
+
calculate: async () => {
|
|
41
|
+
const { currency } = params.context;
|
|
42
|
+
const { defaultPrecision, roundTo } = ProductRound.settings;
|
|
43
|
+
const { calculation = [] } = params.calculationSheet;
|
|
44
|
+
|
|
45
|
+
if (calculation?.length) {
|
|
46
|
+
pricingAdapter.resultSheet().resetCalculation(params.calculationSheet);
|
|
47
|
+
|
|
48
|
+
calculation.forEach((item) => {
|
|
49
|
+
const newAmount = roundTo(item.amount, defaultPrecision, currency);
|
|
50
|
+
pricingAdapter.resultSheet().calculation.push({
|
|
51
|
+
...item,
|
|
52
|
+
amount: newAmount,
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return pricingAdapter.calculate();
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
ProductPricingDirector.registerAdapter(ProductRound);
|
|
@@ -8,7 +8,7 @@ describe('getTaxRate', () => {
|
|
|
8
8
|
expect(getTaxRate({
|
|
9
9
|
product: {} as any,
|
|
10
10
|
order: {} as any,
|
|
11
|
-
})).toBe(0.
|
|
11
|
+
})).toBe(0.081);
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
it('reduced rate', () => {
|
|
@@ -17,7 +17,7 @@ describe('getTaxRate', () => {
|
|
|
17
17
|
tags: ['swiss-tax-category:reduced']
|
|
18
18
|
} as any,
|
|
19
19
|
order: {} as any,
|
|
20
|
-
})).toBe(0.
|
|
20
|
+
})).toBe(0.026);
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it('special rate', () => {
|
|
@@ -26,7 +26,7 @@ describe('getTaxRate', () => {
|
|
|
26
26
|
tags: ['swiss-tax-category:special']
|
|
27
27
|
} as any,
|
|
28
28
|
order: {} as any,
|
|
29
|
-
})).toBe(0.
|
|
29
|
+
})).toBe(0.038);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
it('default rate', () => {
|
|
@@ -35,7 +35,7 @@ describe('getTaxRate', () => {
|
|
|
35
35
|
tags: ['swiss-tax-category:default']
|
|
36
36
|
} as any,
|
|
37
37
|
order: {} as any,
|
|
38
|
-
})).toBe(0.
|
|
38
|
+
})).toBe(0.081);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
})
|
|
@@ -7,8 +7,8 @@ import { SwissTaxCategories } from './tax/ch.js';
|
|
|
7
7
|
export const getTaxRate = (context: { product: Product; order?: Order }) => {
|
|
8
8
|
const { product, order } = context;
|
|
9
9
|
|
|
10
|
-
const productSpecialTaxTag = product.tags?.find(
|
|
11
|
-
|
|
10
|
+
const productSpecialTaxTag = product.tags?.find((tag) =>
|
|
11
|
+
tag?.trim().toLowerCase().startsWith('swiss-tax-category:'),
|
|
12
12
|
);
|
|
13
13
|
const taxCategory =
|
|
14
14
|
Object.values(SwissTaxCategories).find(
|
|
@@ -41,7 +41,7 @@ export const ProductSwissTax: IProductPricingAdapter = {
|
|
|
41
41
|
key: 'shop.unchained.pricing.product-swiss-tax',
|
|
42
42
|
version: '1.0.0',
|
|
43
43
|
label: 'Apply Swiss Tax on Product',
|
|
44
|
-
orderIndex:
|
|
44
|
+
orderIndex: 80,
|
|
45
45
|
|
|
46
46
|
isActivatedFor: () => {
|
|
47
47
|
return true;
|
|
@@ -3,9 +3,10 @@ import {
|
|
|
3
3
|
WarehousingAdapter,
|
|
4
4
|
WarehousingProviderType,
|
|
5
5
|
} from '@unchainedshop/core-warehousing';
|
|
6
|
+
import { generateDbObjectId } from '@unchainedshop/mongodb';
|
|
6
7
|
import { ProductType, ProductContractStandard } from '@unchainedshop/types/products.js';
|
|
7
8
|
import { IWarehousingAdapter, WarehousingError } from '@unchainedshop/types/warehousing.js';
|
|
8
|
-
import {
|
|
9
|
+
import { systemLocale } from '@unchainedshop/utils';
|
|
9
10
|
|
|
10
11
|
const { MINTER_TOKEN_OFFSET = '0' } = process.env;
|
|
11
12
|
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import Sheets from 'node-sheets';
|
|
7
7
|
import { log, LogLevel } from '@unchainedshop/logger';
|
|
8
8
|
import 'abort-controller/polyfill.js';
|
|
9
|
-
import
|
|
9
|
+
import * as lruCache from 'lru-cache';
|
|
10
10
|
import { IWarehousingAdapter } from '@unchainedshop/types/warehousing.js';
|
|
11
11
|
|
|
12
12
|
const { NODE_ENV, GOOGLE_SHEETS_ID, GOOGLE_SHEETS_PRIVATE_KEY_DATA } = process.env;
|
|
@@ -48,7 +48,7 @@ const updateGoogleCache = async (cache) => {
|
|
|
48
48
|
return null;
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
const googleCache = new LRUCache({
|
|
51
|
+
const googleCache = new lruCache.LRUCache({
|
|
52
52
|
max: 500,
|
|
53
53
|
ttl, // 1 second in dev
|
|
54
54
|
allowStale: true,
|